//RJA's attempt at implementation of 74181 in Verilog
//Peeking at someone else's code for Nibbler in Verilog ALU:  https://github.com/bchangip/NibblerCPU/blob/master/alu.sv
//Nibbler only uses 5 functions, but maybe we'll add them all here
//Started with my own code (commented out at the bottom).  It works for F, but carry is wrong for logic modes...
//Switched to using the C code here (slightly modified version of this):  https://github.com/mamedev/historic-mame/blob/master/src/emu/machine/74181.c
//Note:  That code appears to have used the active low logic, so some things were flipped around

module ALU_74181 
	(
	input [3:0] A,  //input A
	input [3:0] B,  //input B
	input [3:0] S,  //Function Selection
	input M, //Mode (Hight for Logic, Low for Arithmetic)
	input CN, //carry in (active low)
	//Outputs need to be registers to be inside always block, but trying without first, meaning async logic...
	output [3:0] F,  //the 4-bit output 
	output AEB,  //zero, A=B
	output CN4, //carry out (active low)  -->  Now F[4] to make it easy
	output P, //propagate
	output G  //generate
	);
   
   		wire cp;
		wire mp;
		
		wire a0;
		wire a1;
		wire a2;
		wire a3;
		
		wire b0;
		wire b1;
		wire b2;
		wire b3;
		
		wire s0;
		wire s1;
		wire s2;
		wire s3;

		wire ap0;
		wire bp0;
		wire ap1;
		wire bp1;
		wire ap2;
		wire bp2;
		wire ap3;
		wire bp3;

		wire aeqb;
		wire pp;
		wire gp;
		
		wire fp0,fp1,fp2,fp3;

	
	
	//always @ *  //RJA Not using registers here to be like the original.  But, this could mean timing will be different on every compilation...
	//begin
	    //RJA flipping CN and M for active high logic
		assign cp = CN;
		assign mp = ~M;
		
		assign a0= A[0];
		assign a1 = A[1];
		assign a2=A[2];
		assign a3= A[3];
		
		assign b0=B[0];
		assign b1=B[1];
		assign b2=B[2];
		assign b3=B[3];
		
		assign s0=S[0];
		assign s1=S[1];
		assign s2=S[2];
		assign s3=S[3];

		//RJA  Propogate and Generate for each pair
		assign ap0 = !(a0 | (b0 & s0) | (s1 & !b0));
		assign bp0 = !((!b0 & s2 & a0) | (a0 & b0 & s3));
		assign ap1 = !(a1 | (b1 & s0) | (s1 & !b1));
		assign bp1 = !((!b1 & s2 & a1) | (a1 & b1 & s3));
		assign ap2 = !(a2 | (b2 & s0) | (s1 & !b2));
		assign bp2 = !((!b2 & s2 & a2) | (a2 & b2 & s3));
		assign ap3 = !(a3 | (b3 & s0) | (s1 & !b3));
		assign bp3 = !((!b3 & s2 & a3) | (a3 & b3 & s3));

		assign fp0 = !(cp & mp) ^ (!ap0 & bp0);
		assign fp1 = (!((mp & ap0) | (mp & bp0 & cp))) ^ (!ap1 & bp1);
		assign fp2 = (!((mp & ap1) | (mp & ap0 & bp1) | (mp & cp & bp0 & bp1))) ^ (!ap2 & bp2);
		assign fp3 = (!((mp & ap2) | (mp & ap1 & bp2) | (mp & ap0 & bp1 & bp2) | (mp & cp & bp0 & bp1 & bp2))) ^ (!ap3 & bp3);
		
		assign F= {fp3,fp2,fp1,fp0};

		assign AEB = fp0 & fp1 & fp2 & fp3;
		//RJA Swapping G and P for active high logic
		assign G = !(bp0 & bp1 & bp2 & bp3);
		assign P = !((ap0 & bp1 & bp2 & bp3) | (ap1 & bp2 & bp3) | (ap2 & bp3) | ap3);  
		//assign CN4 = (!(cp & bp0 & bp1 & bp2 & bp3)) | G; //This was for active low logic
		assign CN4 = ((cp & bp0 & bp1 & bp2 & bp3)) | (!P);  //RJA
	//end
		
	


	//Here is my original where the outputs were registers
	//Code works for F, but carry is wrong for logic modes
	//Doesn't make sense to me, but 74181 has a carry output even for bitwise logic modes.
	//The code above is better in that it matches all that and also has propagate, generate and A=B outputs
	
	/*
	module ALU_74181 
	(
	input [3:0] A,  //input A
	input [3:0] B,  //input B
	input [3:0] S,  //Function Selection
	input M, //Mode (Hight for Logic, Low for Arithmetic)
	input CN, //carry in (active low)
	//Outputs need to be registers to be inside always block, but trying without first, meaning async logic...
	output reg CN4, //carry out (active low)  -->  Now F[4] to make it easy
	output reg Z,  //zero
	output reg [3:0] F  //the 4-bit output /
	);
   
	reg [4:0] result = 0;
	
	always @ *//* seems better, but does the same as --> (CN or M or S or A or B) 
	begin
		if (M==1) 
		begin //Logic Functions
			casex(S)
				4'b0000: 
				begin  //F=not A
					F = ~A;
				end
				4'b0001: 
				begin  //F= not (A or B)
					F = ~(A|B);
				end
				4'b0010: 
				begin  //F= not A and B
					F = (~A)&B;
				end
				4'b0011: 
				begin  //F= 0
					F = 0;
				end		
				4'b0100: 
				begin  //F= not (A and B)
					F = ~(A&B);
				end			
				4'b0101: 
				begin  //F= not B
					F = ~B;
				end			
				4'b0110: 
				begin  //F= A xor B
					F = A^B;
				end					
				4'b0111: 
				begin  //F= A and not B
					F = A&(~B);
				end	
				4'b1000: 
				begin  //F= not A or B
					F = (~A)|B;
				end
				4'b1001: 
				begin  //F= not (A xor B)
					F = ~(A^B);
				end		
				4'b1010: 
				begin  //F= B
					F = B;
				end		
				4'b1011: 
				begin  //F= A&B
					F = A&B;
				end	
				4'b1100: 
				begin  //F= 1
					F = 15;
				end		
				4'b1101: 
				begin  //F= A| notB
					F = A|(~B);
				end		
				4'b1110: 
				begin  //F= A| B
					F = A|B;
				end		
				4'b1111: 
				begin  //F= A
					F = A;
				end				
			endcase
			
			//handle carry and zero
			Z=0;
			CN4=0;
		end
		
		else
			
		begin //Arithmetic Functions
			casex(S)
				4'b0000: 
				begin  //F=A+carry
					result = A+(~CN&1);
					F=result;
				end
				4'b0001: 
				begin  //F=(A or B) +carry
					result = (A|B) + (~CN&1);
					F=result;
				end
				4'b0010: 
				begin  //F= A or not B +carry
					result = (A|(~B&15)) + (~CN&1);
					F=result;
				end		
				4'b0011: 
				begin  //F= 0 or minus 1
					result = (~CN&1) ? 16 : 15;  //zero+carry or -1
					F=result;
				end	
				4'b0100: 
				begin  //F= A plus (A & !B)+carry
					result = A+(A&(~B&15))+ (~CN&1);
					F=result;
				end			
				4'b0101: 
				begin  //F= (A or B) plus (A & !B)+carry
					result = (A|B)+(A&(~B&15))+(~CN&1);
					F=result;
				end	
				4'b0110: 
				begin  //F= A minus B minus 1 + carry --> A+ not B  + carry
					result = A+(~B&15)+(~CN&1);
					F=result;
				end	
				4'b0111: 
				begin  //F= A(not B) minus 1 + carry --> A&~B + 1111 + carry
					result = (A&(~B&15))+15+(~CN&1);
					F=result;
				end	
				4'b1000: 
				begin  //F= A plus A&B +carry
					result = A+(A&B)+(~CN&1);
					F=result;
				end	
				4'b1001: 
				begin  //F= A plus B +carry
					result = A+B+(~CN&1);
					F=result;
				end		
				4'b1010: 
				begin  //F= (A or not B) + A&B +carry
					result = (A|(~B&15))+(A&B)+(~CN&1);
					F=result;
				end		
				4'b1011: 
				begin  //F= A&B -1 +carry
					result = (A&B)+15+(~CN&1);
					F=result;
				end		
				4'b1100: 
				begin  //F= A+A +carry
					result = A+A+(~CN&1);
					F=result;
				end		
				4'b1101: 
				begin  //F= (A|B) + A +carry
					result = (A|B)+A+(~CN&1);
					F=result;
				end	
				4'b1110: 
				begin  //F= (A|(not B)) + A +carry
					result = (A|((~B[3:0])&15))+A+(~CN&1);
					F=result;
				end		
				4'b1111: 
				begin  //F= A-1 +carry
					result = A+15+(~CN&1);
					F=result;
				end					
			endcase
			
			//handle carry and zero
			CN4= result>>4;
			Z = (result==0) ? 1 : 0;

		end
		

   end
   */

 
endmodule // ALU_74181