module TinyFPGA_A2 ( 
//RJA made lower pins A2 output for P2 input and then upper pins A2 input for P2 output
	output p2pin0,
	output p2pin1,
	output p2pin2,
	output p2pin3,
	output p2pin4,
	output p2pin5,
	output pin7_done,
	output pin8_pgmn,
	//output p2pin6,
	//output p2pin7,
	output p2pin6,  
	output p2pin7,  
  
	output p2pin8,
	output p2pin9,
	output p2pin10,
	output p2pin11,
	output p2pin12,
	output p2pin13,
	output p2pin14, 
	output p2pin15
  
	//Not using JTAG pins here although looks like there is a way to use them if need be
	//inout pin12_tdo,
	//inout pin13_tdi,
	//inout pin14_tck,
	//inout pin15_tms,
);

	//Set done and pgmn to high impedance state
	assign pin7_done = 1'bz;
	assign pin8_pgmn = 1'bz;
	


  
	//Clock setup
	wire clk;
	OSCH #(
		.NOM_FREQ("2.08")
		//.NOM_FREQ("133")
	) internal_oscillator_inst (
	.STDBY(1'b0), 
	.OSC(clk)
	); 
	
	//Power on reset, output is resetn, from https://discourse.tinyfpga.com/t/power-on-reset-does-anyone-have-experience/880
	//reg [5:0] reset_cnt = 0;
	//wire resetn = &reset_cnt;
	//always @(posedge clk) begin
	//	reset_cnt <= reset_cnt + !resetn;
	//end
	
	//Global System Reset
	//wire reset;
	//GSR GSR_INST (.GSR (reset));
  
	//ALU 
	//define input and output busses
	wire [3:0] A;
	wire [3:0] F;
	reg [3:0] Data_Bus;   
	wire S3;
	wire S2;
	wire S1;
	wire S0;
	wire [3:0] S={S3,S2,S1,S0};  //ALU function select
	//wire M;  //select between locical (M==1) and arithmetic (M==0) modes
	//wire CN; //inverted carry input
	wire CN4;  //inverted carry output
	wire AEB;    //A=B
	wire P;  //propagate
	wire G; //generate  
	//assign CN = p2pin7;
	//assign M= p2pin6;
	wire CARRYINn;
	wire M;
	//The ZEROn signal is formed with or gates, not using AEB
	wire nZERO;
	assign nZERO = F[3]|F[2]|F[1]|F[0];  
	//the 74182 ALU chip
	ALU_74181 ALU_74181_inst
	(//74181 with positive logic signals (except CN and CN4 are active low)
		//inputs
		.A(A),  //A input (4-bit)
		.B(Data_Bus),  //B input (4-bit)
		.S(S),        //function select input (4-bit)
		.M(M),		   //mode (1=logic or 0=arithmetic)
		.CN(CARRYINn),      //Carry input
		//outputs
		.F(F), //result  (4-bit)
		.AEB(AEB),      //A=B (zero)
		.CN4(CN4),    //Carry output
		.P(P),        //Propagate output
		.G(G)         //Generate output
	);
  
	//timer to slow down clock for counter modules
	reg [31:0] led_timer;
	always @(posedge clk) begin
		led_timer <= led_timer + 1; 
	end
	
	wire Nibbler_clk = led_timer[19];  //was 22
	
  
	//Program Counter
	wire [11:0] Data_Address;
	wire LOADPCn;// = 1'b1;
	//wire Clear_PCn;// = 1'b1;
	reg RESETn;
	wire [11:0] Program_Address;
	wire INCPC;
	//assign Data_Address= 12'h56;  //later to be combination of Program_Address and Fetch
	Program_Counter Program_Counter_inst
	(
		.Address_In(Data_Address), //12-bit input address for load
		.LOADn(LOADPCn),  //Load (active low)
		.CLRn(RESETn),  //Clear (active low)
		//.CLRn(Clear_PCn),  //Clear (active low)
		.CLK(Nibbler_clk),
		.INCPC(INCPC),
		.Address_Out(Program_Address)  //the 12-bit address output 
		
	);

 
	//The 28C64 Program ROM chip with WEn high and OEn and CEn low.
	reg [7:0] PROM_Output;
	reg [7:0] Program_ROM [0:4095];
    initial begin
        //$display("Loading rom.");
        //$readmemh("guess.hex", Program_ROM);
		$readmemh("test1.hex", Program_ROM);
    end
	//RJA making this Synchronous with FPGA clock
	//assign PROM_Output = Program_ROM[Program_Address];
	always @ (posedge clk)
	begin
		PROM_Output <= Program_ROM[Program_Address];
	end

	//Fetch Register
	wire [7:0] Fetch;
	wire [3:0] INSTR = Fetch[7:4];
	wire [3:0] OPRND = Fetch[3:0];
	reg PHASE;
	OctalD_74377 OctalD_74377_inst
	(
		.D(PROM_Output),  //8-bit input
		.CLKENn(PHASE), //Clock Enable (active low)
		.CLK(Nibbler_clk),  //clock
		.Q(Fetch)  //the 8-bit output 		
	);


	wire [6:0] Fetch_Flags;
	//Assign Fetch_Flags
	wire ZEROn;
	wire CARRYn;
	assign Fetch_Flags = {INSTR, CARRYn, ZEROn, PHASE};
	
	//Microcode1
	reg [7:0] Microcode1_Output;
	reg [7:0] Microcode1_ROM [0:127];  //[0:2047];
    initial begin
        //$display("Loading rom.");
        $readmemh("microcode_1.hex", Microcode1_ROM);
    end
	//RJA making this Synchronous with FPGA clock
	//assign PROM_Output = Program_ROM[Program_Address];
	always @ (posedge clk)
	begin
		Microcode1_Output <= Microcode1_ROM[Fetch_Flags];
	end
	
	//Microcode0
	wire [7:0] Microcode0_Output;
	//Switched to IP when design got too big, but didn't actually help, was RAM that was problem
	EBR_ROM_IP EBR_ROM_IP_inst0(
		.Address(Fetch_Flags),
		.OutClock(clk),
		.OutClockEn(1'b1),
		.Reset(1'b0),
		.Q(Microcode0_Output)
	);

	
	
	//Assign Microcode1 outputs
	assign INCPC = Microcode1_Output[7];
	assign LOADPCn = Microcode1_Output[6];
	wire LOADAn;
	assign LOADAn = Microcode1_Output[5];
	wire LOADFLAGSn;
	assign LOADFLAGSn = Microcode1_Output[4];
	assign CARRYINn = Microcode1_Output[3];
	assign M = Microcode1_Output[2];
	assign S3 = Microcode1_Output[1];
	assign S2 = Microcode1_Output[0];
	
	//Assign Microcode0 outputs
	assign S1 = Microcode0_Output[7];
	assign S0 = Microcode0_Output[6];
	wire CSRAMn;
	assign CSRAMn = Microcode0_Output[5];
	wire WERAMn;
	assign WERAMn = Microcode0_Output[4];
	wire OEALUn;
	assign OEALUn = Microcode0_Output[3];
	wire OEINn;
	assign OEINn = Microcode0_Output[2];
	wire OEOPRNDn;
	assign OEOPRNDn = Microcode0_Output[1];
	wire LOADOUTn;
	assign LOADOUTn = Microcode0_Output[0];
	

	
	//Implement phase and reset flag registers
	reg RESET;
	reg PHASEn;
	initial PHASEn= 1'b0;
	initial PHASE= 1'b1;
	reg RESET_IN;// = 1'b0;
	initial RESET_IN = 0;
	
	//forcing a reset at startup 
	
	always @(posedge clk) begin
		if ((led_timer>10)||(RESETn==1))
			RESET_IN=1;  
		else
			RESET_IN=0;
	end
	always @(posedge Nibbler_clk) begin
		RESETn  <= RESET_IN;
		RESET   <= ~RESET_IN;
		PHASE <= PHASEn;
		PHASEn <= ~PHASEn;
	end
	
	//Apply microcode and reset to program counter
	//assign Clear_PCn= RESETn; //1'b1;//led_timer[31];
	//assign Load_PCn = LOADPCn;
	
	//implement ZERO and CARRY registers
	wire [3:0] Zero_Carry_In;
    assign 	Zero_Carry_In = {1'b0,1'b0,nZERO,CN4};
	wire [3:0] Zero_Carry_Out;
	assign ZEROn=Zero_Carry_Out[1];
	assign CARRYn=Zero_Carry_Out[0];
	QuadD_74173 QuadD_74173_inst
	(//Quad D Flip Flop
		.D(Zero_Carry_In),  //4-bit input
		.CLK(Nibbler_clk),  //clock
		.CLR(1'b0), //clear
		.G1n(LOADFLAGSn), //clock gate 1
		.G2n(LOADFLAGSn),
		.Q(Zero_Carry_Out)  //the 4-bit output 
	);
	
	//implement accumulator
	QuadD_74173 QuadD_74173_inst2
	(//Quad D Flip Flop
		.D(F),  //4-bit input
		.CLK(Nibbler_clk),  //clock
		.CLR(1'b0), //clear
		.G1n(LOADAn), //clock gate 1
		.G2n(LOADAn),
		.Q(A)  //the 4-bit output 
	);
	
 
	
	//the CY7C168A RAM (CSn handled by data bus code)
    //Form address bus
	assign Data_Address = {Fetch[3:0],PROM_Output[7:0]};
	wire [3:0] Ram_Output;
	//Switched to this IP when our version was too big for FPGA
	EBR_RAM_DQ_IP EBR_RAM_DQ_IP_inst(
		.Clock(clk),
		.ClockEn(1'b1), 
		.Reset(1'b0),
		.WE(WERAMn),
		.Address(Data_Address),
		.Data(Data_Bus),
		.Q(Ram_Output)
	);

		   
   	//RJA making Data_Bus also Synchronous with FPGA clock
	always @ (posedge clk)
	begin
		if (OEALUn==0) 
			Data_Bus <= F;  //ALU
		else if (!(Nibbler_clk|CSRAMn))
			Data_Bus <= Ram_Output; //RAM
		else if (!OEOPRNDn)
			Data_Bus <=Fetch[3:0]; //Operand
		else
			Data_Bus <= 4'b0000;
	end
		
	
	

	
	

	//Program_Address
	
	assign p2pin0 = A[0];	
	assign p2pin1 = A[1];
	assign p2pin2 = A[2];
	assign p2pin3 = A[3];
	assign p2pin4 = F[0];
	assign p2pin5 = F[1];
	assign p2pin6 = F[2];
	assign p2pin7 = F[3];	
	
	

	assign p2pin8 = Program_Address[0];
	assign p2pin9 = Program_Address[1]; 
	assign p2pin10 = Program_Address[2];
	assign p2pin11 = Program_Address[3];
	


	assign p2pin12 = Program_Address[4]; //PHASE;
	assign p2pin13 = Program_Address[5]; //LOADAn;
	assign p2pin14 = Program_Address[6]; //LOADPCn;
	assign p2pin15 = Program_Address[7]; //INCPC;  

	
	
	

  

endmodule
