// Educational (8 Bit) RISC Processor
// Just like a barebone 8 Bit CPU
//
//
// Designed By:
// Asif Nawaz, Shahzad Jehangir & Ishaq Muhammad - 25 July 2004
// asifnawaz@ieee.org, shahzad_j_k@yahoo.com,ishaq_tehk@yahoo.com
//
// The design originally started out as a CPLD design but due to certain limitations the core was redesigned for FPGA

// Below given 8 Bit processor core is fully synthesizable and successfully tested on Xess Spartan 2 FPGA development board



/************************************/
		/*CPU Instructions*/

`define		Multiply			4'b0000
`define 	Move				4'b0001
`define		Add				4'b0010
`define		Sub				4'b0011
`define		AND				4'b0100
`define		NAND				4'b0101
`define		OR				4'b0110
`define 	NOR				4'b0111
`define 	Load				4'b1000
`define		Ror				4'b1010
`define		Rol				4'b1011
`define		Not				4'b1100
`define		Jump				4'b1111
`define 	Shl				4'b1101
`define		Shr				4'b1110
/*************************************/





/************************************/
		/*Alu Instructions*/

`define		AluMultiply			4'b0000
`define		AluAdd			4'b0010
`define		AluSub			4'b0011
`define		AluAND			4'b0100
`define		AluNAND			4'b0101
`define		AluOR				4'b0110
`define 	AluNOR			4'b0111
`define		AluRor			4'b1010
`define		AluRol				4'b1011
`define		AluNot			4'b1100
`define		AluShl				4'b1101
`define		AluShr				4'b1110
/*************************************/
			  
//Top level module proc which include the code for control unit and instantiate all other sub modules.

	    //Externally generated inputs
module proc (Resetp, Holdp, Clockp,

			//Input&output ports just for simulation purpose
			led1h, led2h, Clock, PCount, pcoutput, Count, R0, R1, R2, R3, A, G);
 
//Port Decleration

	input Clockp;		//Externally generated clock signal
	input Resetp;		//Externally generated active high Reset signal
	input Holdp;		//Externally generated active low Hold signal


//The below given ports are only for simulation purpose

	output [6:0] led1h, led2h;	//input for the seven segment LED display
	output [7:0] PCount;		//8-bit output from the program counter
	output [15:0] pcoutput;		//16-bit instruction fetched from RAM
	output [1:0] Count;		//2-bit output from the machine cycle counter

	output [7:0] R0, R1, R2, R3, A, G;	//8-bit registers
	output Clock;				//output clock signal for simulation	


//Variables of type reg declaration
							 
reg [7:0] BusWires;		//Used to store value for bus BusWires
reg [7:0] Exe;			//Used to store the value to be displayed on 7 segment display
reg [7:0] Data;			//Used to store the decoded data from 16-bit instruction
reg [7:0] Jmp;			//Used to store the jump address
reg [1 : 0] Rx, Ry;		//Used to store the 2-bit value Rx & Ry, which act as input for 2to4 decoder
reg [3 : 0] F;			//Used to store the 4-bit operand of the  16-bit instruction
reg [3:0] AddSub;		//Store 4-bit value which identify operation to be performed by ALU
reg [0:3] Rin, Rout;		//Store 4-bit value which identify one of the 4 registers to be activated for a given operation
reg  Done;			//Store 1-bit value which identify the successful execution of an instruction
reg  Ain, Gin;			//Store two 1-bit values and are used to save data in the A and G register
reg  Extern, Gout;		//Store two 1-bit values and are used in bus BusWires implementation
reg  Jset;			//Store 1-bit value and is used for the jump instruction

//Variables of type wire declaration

wire [7:0] Sum;		//8-bit signal hold the output result from ALU
wire catch;		//1-bit enable signal for decoding of 16-bit instruction
wire JZ;		//1-bit signal used for jump instruction	
wire [1:0] Count;	//2-bit output signal from machine cycle counter
wire [3:0] I;		//4-bit signal which identify the instruction function
wire [0:3] Xreg, Y;	//4-bit signal for the activation of any register form the 4 registers

wire [7:0] R0, R1, R2, R3, A, G;	//These 8 bit signals used to carry data for these registers
wire [7:0] PCount;                  	//8-bit output signal form the program counter
wire [1:8] FuncReg;			//8-bit signal for control unit
wire [1:8] Func; 			//8-bit signal for control unit
wire [15:0] pcoutput;			//16-bit signal from the RAM
wire [6:0] led1, led2, led1h, led2h;	//7-bit signal for Display unit


//1-bit signal used for various operations 
	wire  Clock, ClockS, Reset, Hold, Clockp, Resetp, Locked;

// Delay Locked Loop Buffer

	dll dll(Clockp, ClockS, Locked);

// Assign Clockp signal to Clock wire

	assign Clock = Locked ? ClockS : 1'b0 ;

// Input Buffers for Reset and Hold 
	
	IBUF rst(.I(Resetp), .O(Reset));
	IBUF hld(.I(Holdp), .O(Hold));

// Output Buffers for Display

	OBUF led10(.I(led1[0]), .O(led1h[0]));
	OBUF led11(.I(led1[1]), .O(led1h[1]));
	OBUF led12(.I(led1[2]), .O(led1h[2]));
	OBUF led13(.I(led1[3]), .O(led1h[3]));
	OBUF led14(.I(led1[4]), .O(led1h[4]));
	OBUF led15(.I(led1[5]), .O(led1h[5]));
	OBUF led16(.I(led1[6]), .O(led1h[6]));

	OBUF led20(.I(led2[0]), .O(led2h[0]));
	OBUF led21(.I(led2[1]), .O(led2h[1]));
	OBUF led22(.I(led2[2]), .O(led2h[2]));
	OBUF led23(.I(led2[3]), .O(led2h[3]));
	OBUF led24(.I(led2[4]), .O(led2h[4]));
	OBUF led25(.I(led2[5]), .O(led2h[5]));
	OBUF led26(.I(led2[6]), .O(led2h[6]));


// Clear Signal generation
	
	wire Clear = Reset | (~Locked) ; 

//Program Counter
	 
	pcounter progcounter (Hold, Clear, Clock, Jmp, Jset, PCount, cmd, JZ);
	 
//State Machine Counter
	
	upcount counter (Clear, Clock, Count, cmd, catch);

//Read RAM

	Ram ramreadload(Clock, cmd, PCount, Reset, pcoutput, catch );


//ALU
	alu alu(AddSub, A, BusWires, Sum);

//LED Display

	Display Dis1(Exe[3:0], Clock, Done, led1);
	Display Dis2(Exe[7:4], Clock, Done, led2);
				   
//Control Unit
	//Instruction Decoding

	always @(catch or pcoutput)
		begin
			F = pcoutput[15:12];
			Rx = pcoutput[11:10];
			Ry = pcoutput[9:8];
			Data = pcoutput[7:0];
			
		end

	assign Func = {F, Rx, Ry};
	wire FRin = catch & ~Count[1] & ~Count[0];
	regn functionreg (Func, FRin, Clock, FuncReg);

	assign I = FuncReg[1:4];
	dec2to4 decX (FuncReg[5:6], 1'b1, Xreg);
	dec2to4 decY (FuncReg[7:8], 1'b1, Y);
	
	//Instruction implementation
	
	always @(Count or I or Xreg or Y  or Data or BusWires or G or JZ)
	
	begin	
			Extern = 1'b0;
			Done = 1'b0;
			Ain = 1'b0;
			Gin = 1'b0;
			Gout = 1'b0;
			AddSub = 3'b000;
			Rin = 4'b0;
			Rout = 4'b0;

	begin


			case (Count) 

				2'b00: ;	//No operation in T0
		
				2'b01:   	//define signals in time step T1
				
				begin
					if (JZ == 1)			// Check Jmp
						begin
						Jset = 1'b0;
						Jmp = 8'b00000000;
						end

					case (I)
						
						`Jump: 			//Jump
						begin
							
							Jset = 1'b1;
							Jmp = Data;
							Done = 1'b1;
							Exe = Data;

						end

						`Load: 			//Load
						begin
						
							Extern = 1;
							Rin = Xreg;
							Done = 1'b1;
							Exe = Data;

						end

						`Move: 			//Move
						begin 
			
							Rout = Y;
							Rin = Xreg;
							Done = 1'b1;
							Exe = BusWires;

						end

						`Add, `Sub, `Multiply, `And, `Or, `Not, `Nor, `Nand, `Ror, `Rol, `Shl, `Shr:	//Add, Sub, Logical, Shift
						begin
							Rout = Xreg;
							Ain = 1'b1;
						end
					
					    default: ;

					   endcase
					end
						
				  2'b10:   //define signals in time step T2

					case (I)  

						`Not: 			//Not
						 begin
							AddSub = `AluNot;
							Gin = 1'b1;
						 end

						`Ror: 			//Rotate Right
						 begin
							AddSub = `AluRor;
							Gin = 1'b1;
						 end

						`Rol: 			//Rotate Left
						 begin
							AddSub = `AluRol;
							Gin = 1'b1;
						 end

						`Shl: 			//Shift Left
						 begin
							AddSub = `AluShl;
							Gin = 1'b1;
						 end

						`Shr: 			//Shift Right
						 begin
							AddSub = `AluShl;
							Gin = 1'b1;
						 end
											
						`Add: 			//Add
						 begin
							Rout = Y;
							AddSub = `AluAdd;
							Gin = 1'b1;
						 end

						 `Sub: 			//Sub
						 begin
							Rout = Y;
							AddSub = `AluSub;
							Gin = 1'b1;
						 end

						 `Multiply: 		//Multiplication
						 begin
							Rout = Y;
							AddSub = `AluMultiply;
							Gin = 1'b1;
						 end

						 `And:			//and
						 begin
							Rout = Y;
							AddSub = `AluAnd;
							Gin = 1'b1;
						 end

						 `Nand:			//nand
						 begin
							Rout=Y;
							AddSub = `AluNand;
							Gin=1'b1;
						 end

						 `Or:			//or
						 begin
							Rout=Y;
							AddSub = `AluOr;
							Gin=1'b1;
						 end

						 `Nor: 			//nor
						 begin
							Rout=Y;
							AddSub = `AluNor;
							Gin=1'b1;
						 end

						 default: ;


					   endcase

					2'b11: 		//define signals in time step T2
					begin
					
						case (I) 
	
						`Add, `Sub, `Multiply:			// Add,Sub
						begin
							Gout = 1'b1;
							Rin = Xreg;
							Done = 1'b1;
							Exe = G;
						end

						`And, `Or, `Nand, `Nor, `Not:		//And, Or, Nand, Nor, Not
						begin
							Gout = 1'b1;
							Rin = Xreg;
							Done = 1'b1;
							Exe = G;
						end

						`Ror, `Rol, `Shl, `Shr: 		//Rotate right, Rotate left, Shift left, Shift right
						 begin
							Gout = 1'b1;
							Rin = Xreg;
							Done = 1'b1;
							Exe = G;
						end
						
						default: ;

						endcase

					end	
				endcase
		end
	end		

//Register Creation

	regn reg_0 (BusWires[7:0], Rin[0], Clock, R0);
	regn reg_1 (BusWires[7:0], Rin[1], Clock, R1);
	regn reg_2 (BusWires[7:0], Rin[2], Clock, R2);
	regn reg_3 (BusWires[7:0], Rin[3], Clock, R3);

	regn reg_A (BusWires, Ain, Clock, A);

	regn reg_G (Sum, Gin, Clock, G);


//8 Bit Bus BusWires Implementation using Multiplexer
	
	wire [1:6] Sel = {Rout, Gout, Extern};

	always @(Sel or R0 or R1 or R2 or R3 or G or Data)
	begin
	if (Sel == 6'b100000)
		BusWires = R0;
    	else if (Sel == 6'b010000)
		BusWires = R1;
	else if (Sel == 6'b001000)
		BusWires = R2;
	else if (Sel == 6'b000100)
		BusWires = R3;
	else if (Sel == 6'b000010)
		BusWires = G;
	else if (Sel == 6'b000001)
    		BusWires = Data;
	else 
		BusWires = 8'bz;

	end

endmodule


//Machine Cycle(T) Counter

module upcount(Clear, Clock, Q, cmd, catch);
	
	input Clear, Clock, cmd, catch;
	output [1:0] Q;
	
	wire Clear, Clock, cmd, catch;	
	reg [1:0] Q;

	reg [3:0] RT1;

	
	always @(posedge Clock)
	begin
			if (Clear == 1)
			begin
				Q <= 2'b00;
				RT1 <= 4'b0000;
			end

			else if (cmd == 0)
			begin
				Q <= 2'b00;
				RT1 <= 4'b0000;
			end

			else
			begin
				if (catch == 1'b1)
				begin
					if (RT1 < 8'b0100)
					begin
						RT1 <= RT1 + 1;
						Q <= Q + 1 ;	
					end

					else if (RT1 == 8'b1111)
					begin
						RT1 <= 4'b0100;
					end

					else
						RT1 <= RT1 + 1;
				end
				else
				begin
					Q <= 2'b0;
					RT1 <= 4'b0000;
				end
			end
	end


endmodule


//2-4 Decoder

module dec2to4(W, En, Y);
	input [1:0] W;
	input En;

	wire [1:0] W;
	wire En;

	output [0:3] Y;
	reg [0:3] Y;
	
	always @(W or En)
	begin
		if (En == 1)
			case (W)
				0: Y = 4'b1000;
	   	    		1: Y = 4'b0100;
				2: Y = 4'b0010;
				3: Y = 4'b0001;
			endcase
		else 
			Y = 4'bz;
	end
endmodule


//8-Bit Register

module regn(R, Rin, Clock, Q);
	parameter n = 8;

	input [n-1:0] R;
	input Rin, Clock;

	wire [n-1:0] R;
	wire Rin, Clock;

	output [n-1:0] Q;
	reg [n-1:0] Q;

	always @(posedge Clock)
	 	if (Rin)
			Q <= R;
	
endmodule

// 40K Block SRAM
//Read Ram 
module Ram(Clock, cmd, PcAddr, Reset, Inst, En);

	input Clock, cmd;
	input [7:0] PcAddr;
	input Reset;
	output [15:0] Inst;
	output En;

	wire Clock, cmd;
	wire [7:0] PcAddr;
	wire Reset;

	wire [15:0] Inst;	
	reg En, We, stop;

	reg [7:0]  WAddr, S;
	reg [15:0] WData;
	reg [15:0] Memory [0:10];
	reg enable, DoJob;	

	wire [7:0] Store;
	
	integer  count;

	always @(Reset)
	begin
		if (Reset == 1)
			begin
				Memory[0] =	16'h80FA;
				Memory[1] =	16'h84F5;
				Memory[2] =	16'h8822;
				Memory[3] =	16'h2400;
				Memory[4] =	16'h1D00;
				Memory[5] =	16'h3B00;
				Memory[6] =	16'h4400;
				Memory[7] =	16'h5400;
				Memory[8] =	16'h6400;
				Memory[9] =	16'h7400;
				Memory[10] =	16'hF409;
				enable = 1;	
	
			end
		else
			begin 
				enable = 0;	
			end
	end

		
	always @(posedge Clock)
	begin	
	if (Reset == 1)
		begin
			if (enable == 1)
			begin	
				if (count <= 10)
				begin
	
				WData = Memory[count];
				WAddr <= WAddr + 1;
				count <= count + 1;
				DoJob = 1'b1;
				end
	
			end
		end

	else	
		begin

		DoJob = 1'b0;
		count <= 0;
		WAddr <= 8'b0;
		WData = 16'b0;
		En = cmd;
		end

	end
	
	always @(negedge Clock)
	begin
		if (DoJob == 1)
		begin
			stop = 1'b1;
			We = 1'b1;
			S = WAddr;
		end
		else if (cmd == 1)
		begin
			stop = 1'b1;
			We = 1'b0;
			S = PcAddr; 

		end
		else
		begin
			stop = 1'b0;
			We = 1'b0; 
		end
	end 

	RAMB4_S16 ram(.DO(Inst), .ADDR(S), .CLK(Clock), .DI(WData),
						.EN(stop), .RST(1'b0), .WE(We));

endmodule

//Program Counter

module pcounter(HButton, ClearCr, Clock, Jmp, Jset, Q1, cmd, Jz);
	
	input ClearCr, Clock;
	input HButton;
	input Jset;
	input [7:0] Jmp;

	wire ClearCr, Clock;
	wire HButton;
	wire Jset;
	wire [7:0] Jmp;

	output [7:0] Q1;
	output cmd;
	output Jz;

	reg [7:0] Q1;

	reg  work, cmd, Jz;


	always @(posedge Clock)
	begin
	
		if (ClearCr == 1)
		begin
			Q1 <= 0;
			work = 1'b0;
		end
			
		else	if (HButton == 0)
		begin
			if (work != 1'b1)
			begin 
			cmd = 1'b1;
			work = 1'b1;
				begin
				if (Jset == 1)
					begin
					Q1 <= Jmp;
					Jz = 1'b1;
					end
				else
					Q1 <= Q1 + 1 ;
				end
			end
		end
		else
		begin
			cmd = 1'b0;
			work = 1'b0;
			Jz = 1'b0;
		end
	end	

endmodule



//Arthematic Logic Unit

module alu (Inst, A, BusWires, Result);

	input [3:0] Inst;
	input [7:0] A, BusWires;

	wire [3:0] Inst;
	wire [7:0] A, BusWires;

	output [7:0] Result;
	//output Cout, Zout, Sout;

	reg [7:0] Result;
	reg Zout, Sout, Cout;
			
	always @(Inst  or A or BusWires or Result)

	begin
		Zout	= 1'b0;
		Sout	= 1'b0;
		Cout = 1'b0;
		Result = 8'b0;


    	case (Inst)  // synopsis  parallel_case
	

		`AluMultiply:	
					begin 
					{Cout,Result}  = (A * BusWires);
					//Cout = Result[8]; 
					if (Result == 8'h00) 
					Zout = 1'b1; 
					if (Result[7] == 1) 
					Sout = 1'b1; 
					end

		`AluShl: 		Result = {A[6:0], 1'b0};				
		`AluShr: 		Result = {1'b0, A[7:1]};

		`AluRol: 		Result = {A[6:0], A[7]};
		`AluRor: 		Result = {A[0], A[7:1]};

		`AluAdd:		begin 
					{Cout,Result}  = (A + BusWires);
					//Cout = Result[8];
					if (Result == 8'h00) 
					Zout = 1'b1; 
					if (Result[7] == 1) 
					Sout = 1'b1; 
					end

		`AluSub:		begin 
					{Cout,Result}  = (A - BusWires) ;
					//Cout = Result[8];
					if (Result == 8'h00) 
					Zout = 1'b1; 
					if (Result[7] == 1) 
					Sout = 1'b1; 
					end

		`AluAnd: 		Result =   A & BusWires; 
		`AluNand:		Result =  ~(A & BusWires); 
		`AluOr:  		Result =   A | BusWires;
		`AluNor: 		Result =  ~(A | BusWires);
		`AluNot:		Result =	~(A);

		default: 		begin
						Zout	= 1'b0;
						Sout	= 1'b0;
						Cout = 1'b0;
						Result = 8'b0;
					end

		
	endcase
	
	end
	
endmodule





/* Led: The 7 segment display */

module Display(buscontents, clk, Done, led);

	input [3:0] buscontents;
	input clk, Done;

	wire [3:0] buscontents;
	wire clk, Done;

	output [6:0] led;

	reg[6:0]	led;

	always @ (posedge clk)
		if (Done == 1)
		begin
			case (buscontents)   // synopsis full_case parallel_case

				4'b0000: led = 7'b1110111;
				4'b0001: led = 7'b0010010;
				4'b0010: led = 7'b1011101;
				4'b0011: led = 7'b1011011;
				4'b0100: led = 7'b0111010;
				4'b0101: led = 7'b1101011;
				4'b0110: led = 7'b1101111;
				4'b0111: led = 7'b1010010;
				4'b1000: led = 7'b1111111;
				4'b1001: led = 7'b1111011;
				4'b1010: led = 7'b1111110;
				4'b1011: led = 7'b0101111;
				4'b1100: led = 7'b0001101;
				4'b1101: led = 7'b0011111;
				4'b1110: led = 7'b1101101;
				4'b1111: led = 7'b1101100;
   	   		endcase
		end

endmodule


//   Delay Lock Loops and Global clock buffers instantiation    
 
module dll(CLKIN, CLK1X, LOCKED2X);

input CLKIN;
output CLK1X, LOCKED2X;

wire CLK1X;

wire CLKIN_w, CLK1X_dll, LOCKED2X;


	IBUFG clkpad (.I(CLKIN), .O(CLKIN_w));

	CLKDLL dll2x (.CLKIN(CLKIN_w), .CLKFB(CLK1X), .RST(1'b0), 
	              .CLK0(CLK1X_dll), .CLK90(), .CLK180(), .CLK270(),
	              .CLK2X(), .CLKDV(), .LOCKED(LOCKED2X));

	BUFG   clk2xg (.I(CLK1X_dll),  .O(CLK1X));

	//OBUF   lckpad (.I(LOCKED2X), .O(LOCKED));

endmodule
