`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: Jürgen Böhm
// 
// Create Date:    02:08:39 02/18/2007 
// Design Name: 
// Module Name:    cpu 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////


module comp_lt ( a, b, is_lt );

input[31:0] a,b;
output reg is_lt;

always @(a,b)
	begin
		if (a[31]==b[31])
			is_lt <= (a[30:0] < b[30:0]);
		else
			is_lt <= a[31];		
	end

endmodule


module alu ( opcode, opA, opB, opC, aluOut, overflow, carry, zero, clk );

input[31:0] opA, opB, opC;

output[31:0] aluOut;
input[5:0] opcode;

output overflow, carry, zero;
input clk;

reg[31:0] aluOut;

assign zero = (aluOut == 0);

// the comparators

wire aLTb;
wire aGTb;

comp_lt comp_lt0 (opA, opB, aLTb );
comp_lt comp_lt1 (opB, opA, aGTb );

wire aEQb;
wire aLTEb;
wire aGTEb;

assign aEQb = (opA == opB);
assign aLTEb = aLTb | aEQb;
assign aGTEb = aGTb | aEQb;


// the main alu

wire[31:0] lenVect = 32'd12 + (opA << 2);

always @(posedge clk)
	begin
		case (opcode)
			0: aluOut <= opA + opB;
			1: aluOut <= opA - opB;
			2: aluOut <= aLTEb ? 1 : opC;
			3: aluOut <= aGTEb ? 1 : opC;
			4: aluOut <= aLTb ? 1 : opC;
			5: aluOut <= aGTb ? 1 : opC;
			6: aluOut <= aEQb ? 1: opC;
			11: aluOut <= opA | opB;
			12: aluOut <= opA & opB;
			13: aluOut <= ~(opA | opB);
			14: begin
					case (opB[6:2])
						0: aluOut <= opA >> 0;
						1: aluOut <= opA >> 1;
						2: aluOut <= opA >> 2;
						3: aluOut <= opA >> 3;
						4: aluOut <= opA >> 4;
						5: aluOut <= opA >> 5;
						6: aluOut <= opA >> 6;
						7: aluOut <= opA >> 7;
						8: aluOut <= opA >> 8;
						9: aluOut <= opA >> 9;
						10: aluOut <= opA >> 10;
						11: aluOut <= opA >> 11;
						12: aluOut <= opA >> 12;
						13: aluOut <= opA >> 13;
						14: aluOut <= opA >> 14;
						15: aluOut <= opA >> 15;
						16: aluOut <= opA >> 16;
						17: aluOut <= opA >> 17;
						18: aluOut <= opA >> 18;
						19: aluOut <= opA >> 19;
						20: aluOut <= opA >> 20;
						21: aluOut <= opA >> 21;
						22: aluOut <= opA >> 22;
						23: aluOut <= opA >> 23;
						24: aluOut <= opA >> 24;
						25: aluOut <= opA >> 25;
						26: aluOut <= opA >> 26;
						27: aluOut <= opA >> 27;
						28: aluOut <= opA >> 28;
						29: aluOut <= opA >> 29;
						30: aluOut <= opA >> 30;
						31: aluOut <= opA >> 31;
					endcase
				 end
			15: begin
					case (opB[6:2])
						0: aluOut <= opA << 0;
						1: aluOut <= opA << 1;
						2: aluOut <= opA << 2;
						3: aluOut <= opA << 3;
						4: aluOut <= opA << 4;
						5: aluOut <= opA << 5;
						6: aluOut <= opA << 6;
						7: aluOut <= opA << 7;
						8: aluOut <= opA << 8;
						9: aluOut <= opA << 9;
						10: aluOut <= opA << 10;
						11: aluOut <= opA << 11;
						12: aluOut <= opA << 12;
						13: aluOut <= opA << 13;
						14: aluOut <= opA << 14;
						15: aluOut <= opA << 15;
						16: aluOut <= opA << 16;
						17: aluOut <= opA << 17;
						18: aluOut <= opA << 18;
						19: aluOut <= opA << 19;
						20: aluOut <= opA << 20;
						21: aluOut <= opA << 21;
						22: aluOut <= opA << 22;
						23: aluOut <= opA << 23;
						24: aluOut <= opA << 24;
						25: aluOut <= opA << 25;
						26: aluOut <= opA << 26;
						27: aluOut <= opA << 27;
						28: aluOut <= opA << 28;
						29: aluOut <= opA << 29;
						30: aluOut <= opA << 30;
						31: aluOut <= opA << 31;
					endcase
				 end
			32: if (|(opB[2:0]))
						begin
							aluOut <= {opB[31:3],3'b0} + 32'd8;
						end
					else
						begin
							aluOut <= opB;
						end
				 
			33: aluOut <= lenVect;
			34: aluOut <= {opB[31:2],2'b10};
			35: aluOut <= {opB[31:2],2'b00} + opA;
			36: aluOut <= opA + (opB >> 2);
			default : aluOut <= opB;
		endcase
	end

endmodule




module cpu(	addr,
				data,
				readmem,
				writemem,
				intrq,
				type,
				rst,
				clk
				);

output[31:0] addr;
inout[31:0] data;

output readmem;
output writemem;
input intrq;

output[1:0] type;


input rst;
input clk;

//registered output lines


reg readmem;
reg writemem;

reg[1:0] type;

// special provision for data in/out

reg[31:0] datao;
reg dataeno;

// assign data = dataeno ? datao : 32'bz;


// registers


reg[31:0] addro;

assign addr = addro;

reg[31:0] csp, dsp;  // code stack pointer , data stack pointer

reg[31:0] ir; 

reg[31:0] pc;

wire[31:0] datamem; // data input buffer;

wire[31:0] datamem2 = {datamem[29:0],2'b0};

reg[31:0] litbase;

reg[31:0] template;





reg[31:0] regA;
reg[31:0] regB;

reg[31:0] regC;


reg[31:0] regD;

reg[31:0] regE;


reg[31:0] tos;

wire[31:0] regA2 = {2'b0,regA[31:2]};


// the ALU

wire[31:0] aluOut;

wire[5:0] aluOp;

wire overflow, carry, zero;

wire[31:0] opA;

alu alu0 (.opcode(aluOp),.opA(opA),.opB(tos),.opC(regC),
									.aluOut(aluOut),.overflow(overflow),.carry(carry),.zero(zero),.clk(clk));


wire[5:0] aluOp_h;

assign aluOp = use_aluOp_h ? aluOp_h : ir[29:24];

wire is_nil = (tos == regC);

// the bus structures and multiplexors




// data bus




// derived signal d from ir

wire[31:0] d;
wire[15:0] d1;

assign d1 = ir[15:0];

assign d = {{14{d1[15]}},d1,1'b0,1'b0};

wire[31:0] litbase_plus_d = litbase + d;

//assign d = 32'd4;

wire[31:0] dsp_plus_d;
wire[31:0] csp_plus_d;
wire[31:0] dsp_minus_d;
wire[31:0] csp_minus_d;


assign dsp_plus_d = dsp + d;
assign csp_plus_d = csp + d;

assign dsp_minus_d = dsp - d;
assign csp_minus_d = csp - d;


wire[31:0] dsp_4;
wire[31:0] dsp_8;

wire[31:0] csp_4;


wire[31:0] dsp_m_4;
wire[31:0] csp_m_4;


assign csp_4 = csp + 32'd4;

assign dsp_m_4 = dsp - 32'd4;
assign csp_m_4 = csp - 32'd4;

assign dsp_4 = dsp + 32'd4;
assign dsp_8 = dsp + 32'd8;

wire[31:0] dsp_plus_dm1 = dsp_m_4 + d;


wire[31:0] litbase_addr = template + 32'd16;

wire[31:0] tp_4 = template + 32'd4;

wire[31:0] pc_4 = pc + 32'd4;

wire[31:0] regA_8 = regA  + 32'd8;

// dat


reg[31:0] datbus;

assign opA = datbus;

wire[4:0] dat_source;

`define vect_header_tag 32'd5
`define clos_header_tag 32'd13
`define val_3 32'd3

`define val_8 32'd8
`define val_12 32'd12
`define val_16 32'd16

always @(regA, regB, regC, regD, regE, litbase, datamem, aluOut, dat_source, tos, 
					litbase_addr, template)
	begin
		case (dat_source)
		0: begin datbus <= datamem; end
		1: begin datbus <= aluOut; end
		2: begin datbus <= regA; end
		3: begin datbus <= regB; end
		4: begin datbus <= regC; end
		5: begin datbus <= regD; end
		6: begin datbus <= litbase; end
		7: begin datbus <= tos; end
		8: begin datbus <= litbase_addr; end
		9: begin datbus <= template; end
		10: begin datbus <= regE; end
		11: begin datbus <= pc_4; end
		12: begin datbus <= d; end
		13: begin datbus <= datamem2; end
		14: begin datbus <= regA2; end
		16: begin datbus <= `val_8; end
		17: begin datbus <= `val_12; end
		18: begin datbus <= `val_16; end
		19: begin datbus <= `val_3; end
		20: begin datbus <= `vect_header_tag; end
		21: begin datbus <= `clos_header_tag; end
		23: begin datbus <= 32'h0; end
		24: begin datbus <= 32'h01020304; end
		default: begin datbus <= regA; end
		endcase
	end
	

wire[4:0] dat_dest;

reg[31:0] dummy;

always @(posedge clk)
	begin
		case (dat_dest)
			1: ir <= datbus;
			3: tos <= datbus;
			4: regA <= datbus;
			5: regB <= datbus;
			6: regC <= datbus;
			7: regD <= datbus;
			8: litbase <= datbus;
			9: template <= datbus;
			10: regA <= regA + 4;
			11: regE <= datbus;
			12: tos <= tos + 4;
			13: tos <= tos - 4;
			default: dummy <= datbus;
		endcase
	end


// data out bus

assign datamem = ~dataeno ? data : 32'bz;
assign data = dataeno ? datbus : 32'bz;




// addr

wire[4:0] addr_source;

`define niladdr 32'h0000


always @(dsp, dsp_4, dsp_m_4, dsp_plus_d, 
			csp, csp_4, csp_m_4, csp_plus_d, pc, aluOut, litbase, regA, regB, regD, addr_source)
	begin
		case (addr_source)
			5'd0: addro <= dsp;
			5'd1: addro <= dsp_4;
			5'd2: addro <= dsp_m_4;
			5'd3: addro <= dsp_plus_d;
			5'd4: addro <= csp;
			5'd5: addro <= csp_4;
			5'd6: addro <= csp_m_4;
			5'd7: addro <= csp_plus_d;
			5'd8: addro <= pc;
			5'd9: addro <= aluOut;
			5'd10: addro <= regA;
			5'd11: addro <= regB;
			5'd12: addro <= regD;
			5'd13: addro <= litbase_plus_d;
			5'd14: addro <= litbase_addr;
			5'd15: addro <= dsp_plus_dm1;
			5'd16: addro <= tos;
			5'd17: addro <= regA_8;
			5'd18: addro <= tp_4;
			5'd29: addro <= 32'h40;
			5'd30: addro <= `niladdr;
			default: addro <= 32'bz;
		endcase
	end

// cdsp

wire[2:0] cdsp_dest;

wire[2:0] cdsp_source;

reg[31:0] cdspbus;


always @(csp, dsp, csp_plus_d, dsp_plus_d, csp_minus_d, dsp_minus_d, csp_4, dsp_4, csp_m_4, dsp_m_4, cdsp_source)
	begin
		case (cdsp_source)
			3'd0: cdspbus <= csp_plus_d;
			3'd1: cdspbus <= dsp_plus_d;
			3'd2: cdspbus <= csp_minus_d;
			3'd3: cdspbus <= dsp_minus_d;
			3'd4: cdspbus <= csp_4;
			3'd5: cdspbus <= dsp_4;
			3'd6: cdspbus <= csp_m_4;
			3'd7: cdspbus <= dsp_m_4;
		endcase
	end


always @(posedge clk or posedge rst)
	if (rst)
		begin
			csp <= 32'h1000;
			dsp <= 32'h2000;
		end
	else
	begin
		case (cdsp_dest)
			3'd0: csp <= cdspbus;
			3'd1: dsp <= cdspbus;
			3'd2: csp <= datbus;
			3'd3: dsp <= datbus;
			default: begin
							dsp <= dsp;
							csp <= csp;
						end
		endcase
	end
	
// pcb

wire[2:0] pcb_source;

always @(posedge clk)
	begin
			case (pcb_source)
				3'd0: pc <= pc_4;
				3'd1: pc <= pc + d;
				3'd2: pc <= datbus;
				3'd3: begin
								if (is_nil)
									begin
										pc <= pc + d;
									end
								else
									begin
										pc <= pc_4;
									end
				end
				default: pc <= pc;
			endcase
	end



// control ir read

reg irRead;




// miscellaneous

always @(dataeno)
	begin
		writemem <= dataeno;
	end
	

// micro program control

wire[31:0] mic_inst;
wire[31:0] mic_inst_h;

reg[9:0] micr_pc;

wire[9:0] next_micr_pc;

assign next_micr_pc = micr_pc + 1;


assign addr_source = mic_inst[31:27];
assign dat_source = mic_inst[26:22];
assign dat_dest = mic_inst[21:17];
assign cdsp_source = mic_inst[16:14];
assign cdsp_dest = mic_inst[13:11];
assign pcb_source = mic_inst[10:8];

wire data_eno_mic = mic_inst[6:6];

wire read_mem = mic_inst[7:7];

wire[3:0] mic_next = mic_inst[3:0];

wire dispatch = mic_inst_h[6:6];

wire to_page_zero = mic_inst_h[7:7];

wire[1:0] mtyp = mic_inst_h[9:8];

assign aluOp_h = mic_inst_h[5:0];

assign use_aluOp_h = mic_inst_h[10:10];


always @(mtyp)
	begin
		type <= mtyp;
	end

always @(read_mem)
	begin
		readmem <= read_mem;
	end



always @(data_eno_mic)
	begin
		dataeno <= data_eno_mic;
	end



// main

always @(posedge clk or posedge rst)
	begin
		if (rst) begin			
			micr_pc <= 63*16;
		end else begin
			if (to_page_zero)
				begin
					micr_pc <= {5'b0, mic_next};
				end
			else if (dispatch)
				begin
					micr_pc <= {datamem[21:16],mic_next};
				end
			else
				begin
					micr_pc <= {micr_pc[9:4],mic_next};
				end
		end
	end


micro_store mcs0 ( .address({micr_pc[9:0]}), .data(mic_inst), .read_en(1'b1), .ce(1'b1)); 
micro_store_1 mcs1 ( .address({micr_pc[9:0]}), .data(mic_inst_h), .read_en(1'b1), .ce(1'b1));


endmodule


//-----------------------------------------------------
// Design Name : rom_using_file
// File Name   : rom_using_file.v
// Function    : ROM using readmemh
// Coder       : Deepak Kumar Tala & JB
//-----------------------------------------------------
module micro_store (
address,
data,
read_en, // Read Enable 
ce        // Chip Enable
);

input[9:0] address;
output[31:0] data; 
input read_en; 
input ce; 

reg[31:0] mem[0:1024] ;  

assign data = (ce && read_en) ? mem[address] : 32'b0;

initial begin
  $readmemb("mainmask.micdata", mem); // memory_list is memory file
end

endmodule

module micro_store_1 (
address,
data,
read_en, // Read Enable 
ce        // Chip Enable
);

input[9:0] address;
output[31:0] data; 
input read_en; 
input ce; 

reg[31:0] mem[0:1024] ;  

assign data = (ce && read_en) ? mem[address] : 32'b0;

initial begin
  $readmemb("auxmask.micdata", mem); // memory_list is memory file
end

endmodule



module mem_sync (
addr,
data,
en,
write,
clk
);

input[31:0] addr;

inout[31:0] data;

input[3:0] en;

input[3:0] write;

input clk;

`define memsize (32*1024 - 1)

reg[31:0] mem[0:`memsize];

reg[7:0] mem0[0:`memsize];
reg[7:0] mem1[0:`memsize];
reg[7:0] mem2[0:`memsize];
reg[7:0] mem3[0:`memsize];

reg[31:0] dataout;

assign data = (~(|write) & (|en_r)) ? dataout : 32'bz;

reg[3:0] en_r;

reg[7:0] val0;
reg[7:0] val1;
reg[7:0] val2;
reg[7:0] val3;


always @(posedge clk)
	begin
		if (|write)
			begin
				if (write[0])
					mem0[addr[16:2]] <= data[7:0];
				if (write[1])
					mem1[addr[16:2]] <= data[15:8];
				if (write[2])
					mem2[addr[16:2]] <= data[23:16];
				if (write[3])
					mem3[addr[16:2]] <=  data[31:24];
				en_r <= en;
			end
		else
			begin
				dataout <= {mem3[addr[16:2]],mem2[addr[16:2]],mem1[addr[16:2]],mem0[addr[16:2]]};
				en_r <= en;
			end
	end

integer i;
reg[31:0] val;

initial begin
//	$readmemh("main-mem-dump.txt", mem);
	$readmemh("akt-test.dump", mem);
	#1	
	for (i = 0; i < `memsize; i = i + 1) begin
		val = mem[i];
		mem0[i] = val[7:0];
		mem1[i] = val[15:8];
		mem2[i] = val[23:16];
		mem3[i] = val[31:24];
	end
end

initial begin
	#499990
	for (i = 0; i < `memsize; i = i + 1) begin
		mem[i] = {mem3[i],mem2[i],mem1[i],mem0[i]}; 
	end
	$writememh("mem-result-dump.txt", mem);


end


endmodule

















