`include	"defines.v"
// ----------------------------------------------------------------------------------------
// "il" datapath
// ----------------------------------------------------------------------------------------
module datapath (
		clk, 			// horizontal
		clk_n, 
		reset,
		panel_pc_load,
		panel_pc_data,
		panel_mem_enable,
		panel_mem_write,
		panel_mem_addr,
		panel_mem_write_data,
		panel_mem_data,
		muxsel, 		// selettore
		PCBUS,		// registri 
		IRBUS, 
		ACBUS, 
		INBUS, 		
		SWREG,		// questo in ingresso
		link, 		// link ecc.
		link_sel, 
		overflow_out, 
		CYF, 			
		REGLOADx, 	// segnali comando
		ALU_OPC, 
		we_n, 		
		MB0, 			// MB=0
		MB1X,
		DFBUS,
		IFBUS,
		use_df,		// usa il DF invece dell'IF
		FLAGS,		// current flags content for GTF
		FLAGSBUS
		); 		
		
	input [3:0] muxsel;
	input [4:0]  ALU_OPC;// ALU control
	input [11:0] SWREG;
	input panel_pc_load;
	input [11:0] panel_pc_data;
	input panel_mem_enable;
	input panel_mem_write;
	input [11:0] panel_mem_addr;
	input [11:0] panel_mem_write_data;
	output [11:0] panel_mem_data;
	input [11:0] FLAGS;
	input clk;
	input clk_n;
	input we_n;	
	input use_df;	
	input [7:0] REGLOADx;			
	input CYF; 			// CARRY FLAG
	output [11:0]IRBUS;
	input  [11:0]INBUS;
	output [11:0]ACBUS;
	output overflow_out;
	input reset;
	input [2:0]link_sel;
	output link;
	output [11:0] FLAGSBUS;	// value to be used for FLAGS setting (RTF) - stored here in a register

	wire link_n;
	wire linkD;
	wire overflow_in;
	output MB0; // vero se MB=0
	output MB1X;
	output [11:0]PCBUS;
	wire [11:0] MUXO;		// ALU A
	wire [11:0] PCBUS;	// bus dati in uscita da PC
	wire [11:0] MABUS;	// bus dati in uscita da MA
	wire [11:0] MBBUS;	// bus dati in uscita da MB
	wire [11:0] ALUBUS;	// 
	wire [11:0] memout;
	wire toLSB, toMSB;
	wire LR_load;
	wire [11:0] led_conn;
	input [2:0] IFBUS;
	input [2:0] DFBUS;
	wire [11:0] MQBUS;
	wire [14:0] XMABUS;	// bus indirizzi esteso

	reg [8:0] REGLOAD;

	always @(*) begin
		case (REGLOADx)
			`dPC:    REGLOAD = 9'b111111110;
			`dMA:    REGLOAD = 9'b111111101;
			`dIR:    REGLOAD = 9'b111111011;
			`dAC:    REGLOAD = 9'b111100111; // two bits active
			`dMB:    REGLOAD = 9'b111011111;
			`dAB:    REGLOAD = 9'b111011101; // MA + MB
			`dSRA:   REGLOAD = 9'b111101111;
			`dSLA:   REGLOAD = 9'b111110111;
			`dMEM:   REGLOAD = 9'b101111111;
			`dMQ:    REGLOAD = 9'b110111111;
			`dXX:    REGLOAD = 9'b111111111;
			`dFLAGS: REGLOAD = 9'b011111111;
			`dPCMEM: REGLOAD = 9'b101111110;	// replaces old dPC & dMEM
			default: REGLOAD = 9'b111111111;
		endcase
	end
	
	// -------------------------------------------------------------------------------------------------
	// RAM sistema, usa il modulo block generato da ISE
	// -------------------------------------------------------------------------------------------------
	wire ram_wea;
	wire [11:0] ram_dina;

	assign ram_wea  = panel_mem_enable ? panel_mem_write      : ~we_n;
	assign ram_dina = panel_mem_enable ? panel_mem_write_data : MBBUS;

	blk_ram16kx12 block_ram (.clk(clk_n), .wea(ram_wea), .addra(XMABUS), .dina(ram_dina), .douta(memout));

	assign panel_mem_data = memout;
		
	// -------------------------------------------------------------------------------------------------
	// ALU - qualcuno le deve fare
	// -------------------------------------------------------------------------------------------------
	ALU the_alu (.CONT(ALU_OPC), .A(MUXO), .B(ACBUS), .Y(ALUBUS), .CY(CYF), .OVERFLOW(overflow_in));
	
	// -------------------------------------------------------------------------------------------------
	// MUX - tutto ruota attorno a questo sole
	// -------------------------------------------------------------------------------------------------
	mux16in_12w the_mux (.select(muxsel), 
		.a(PCBUS),			 			
		.b(MBBUS),						
		.c(MABUS),						
		.d(ACBUS),	    				

		.e(12'd0),	
		.f(SWREG), 
		.g(memout), 
		.h(IRBUS[7] ? {MBBUS[11:7],IRBUS[6:0]} : {5'b00000,IRBUS[6:0]}), 	// Effective Address - can be a) an address out of 128 in base page
                                                                        // b) an address out of 128 in the page of MBBUS[11:7]
                                                                        // IRBUS[7] is instruction MEMORY PAGE bit - if 1 uses the page where
																								// the instruction is, otherwise page 0
		.i(INBUS),
		.j(MQBUS),
		.k(FLAGS),																			// for GTF
		.l(12'd0),

		.m(12'd0),
		.n(12'd0),
		.o(12'd0),
		.p(12'd0),
		.y(MUXO));	
	
		// Uso di REGLOAD
		// +-----+-----+-----+-----+-----+-----+-----+-----+
		//	|  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
		// +-----+-----+-----+-----+-----+-----+-----+-----+
		// | WEn |  MQ |  MB | AC1 | AC2 |  IR |  MA |  PC |
		// +-----+-----+-----+-----+-----+-----+-----+-----+
		// R1 = registro ausiliario
	
	
	// -------------------------------------------------------------------------------------------------
	// REGISTRI PRINCIPALI
	// -------------------------------------------------------------------------------------------------
	// PC has a console-defined reset value.  This replaces the old
	// microprogram boot trick that loaded 0200 through the virtual SWREG.
	// Later, ADDR LOAD will load PC through the normal datapath path.
	R12_RESET0200 PC (.in(ALUBUS), .out(PCBUS), .clk(clk_n), .reset(reset), .load_n(REGLOAD[0]),
	                  .console_load(panel_pc_load), .console_data(panel_pc_data));
	R12 MA (.in(ALUBUS), .out(MABUS), .clk(clk_n), .reset(reset), .load_n(REGLOAD[1]));
	R12 IR (.in(ALUBUS), .out(IRBUS), .clk(clk_n), .reset(reset), .load_n(REGLOAD[2]));
	R12 MB (.in(ALUBUS), .out(MBBUS), .clk(clk_n), .reset(reset), .load_n(REGLOAD[5]));
	R12 MQ (.in(ALUBUS), .out(MQBUS), .clk(clk_n), .reset(reset), .load_n(REGLOAD[6]));

	// RTF copies AC into FLAGSBUS.
	// The datapath uses FLAGSBUS[11] to restore LINK.
	// Other restored flags are owned by external control modules:
	//   FLAGSBUS[8]   CPU interrupt inhibit
	//   FLAGSBUS[7]   CPU interrupt enable, if implemented as restored state
	//   FLAGSBUS[5:0] memory extension save field
	// Therefore FLAGSBUS must be exported to the CPU / memory extension logic.
	
	// when REGLOAD[8]=0 we executed a RTF instruction and the accumulator contains the flags to be restored
	// (more precisely we are executing a uinstruction with dFLAGS destination)
	// 
	R12 FLAGS_reg (.in(ALUBUS), .out(FLAGSBUS), .clk(clk_n), .reset(reset), .load_n(REGLOAD[8]));
	
	assign XMABUS = panel_mem_enable ? {3'b000, panel_mem_addr} :
	                 (use_df ? {DFBUS,MABUS} : {IFBUS,MABUS});	 	
		
	assign toLSB = (link_sel == `lkNOP) ? ACBUS[11] : link;
	assign toMSB = (link_sel == `lkNOP) ? ACBUS[0] : link;

	// -------------------------------------------------------------------------------------------------
	// ACCUMULATORE
	// acc � diverso perch� deve fare +cose
	// acc deve latchare dati sul negedge in quanto sono predisposti da ALU al posedge 
	// l'operazione di shift avviene in seguito a un comando di latch, quindi secondo me
	// anche questo deve avvenire su negedge *** 18.4.2013 ***
	// -------------------------------------------------------------------------------------------------
	Accumulator AC (.in(ALUBUS), .out(ACBUS), .clk(clk_n), .reset(reset), .in_sr(toMSB), .in_sl (toLSB), 
	                .opc(~REGLOAD[4:3]));	

	// se il destinatario � l'AC, allora si deve latchare overlow_in (direttamente dall'ALU)
	// era su clk, spostato su clk_n, deve attendere che i dati in uscita da ALU siano stabili
	ff_D_ena OVERFLOW (.clk(clk_n), .reset(reset), .D_en(~(REGLOAD[4] | REGLOAD[3])), 
	                   .D(overflow_in), .Q(), .Q_n(overflow_out));

	// -------------------------------------------------------------------------------------------------
	// LINK
	// -------------------------------------------------------------------------------------------------
	// FF del LINK e relativa logica (vedi libro)
	ttl_74151X LINK_MUX(.select(link_sel), 
		.a(link),		// i.e., = unchanged
		.b(link_n),
		.c(ACBUS[0]),
		.d(ACBUS[11]),
		.e(1'b0),				// clear
		.f(1'b1),				// set
		.g(FLAGSBUS[11]),		// restore from FLAGSBUS
		.h(1'b0), 				// not used
		.y(linkD));				// output

   // *** 18.4.2013 *** deve aspettare il comando link_sel stabile (nella uOP)
	// e quindi deve andare su negedge
	ff_D_ena LINK (.clk(clk_n), .reset(reset), .D_en(1'b1), .D(linkD), .Q(link), .Q_n(link_n));
	
	assign MB0 = ~(|MBBUS);
   assign MB1X = ~(|MABUS[11:4]) & MABUS[3];
	
`ifdef trace_xec
	initial
		begin
		//mcd = $fopen("xec_log", "w");
		//$write(mcd, "Pippo %d", 1);
		//$write(mcd, "Pippo");
		//$fclose(mcd);
//			$monitor("[%d %d] %8b PC=%04o MA=%04o MB=%04o MO=%04o MuxSel=%d ALUA(MUXO)=%04o ALUB(AC)=%04o ALUBUS=%04o ALU_opc=%5b %1b IR=%04o AC=%04o LK=%1d", 
//			$time, 1, REGLOAD, PCBUS, MABUS, MBBUS, memout, muxsel, MUXO, ACBUS, ALUBUS, ALU_OPC, CYF, IRBUS, ACBUS, link);

//			$monitor("PC=%04o            MA=%04o MB=%04o MO=%04o IR=%04o AC=%04o LK=%1d", 
//			PCBUS, MABUS, MBBUS, memout, IRBUS, ACBUS, link);

		end

	always @ (uPCBUS)
		if (uPCBUS == 8'd6)
		begin
			mcd = $fopen("xec_log", "a");
			$fwrite(mcd, "[%d] PC=%o IR=%o AC=%o\n", $time,MABUS, IRBUS, ACBUS);
			$fclose(mcd);
		end
`endif 
endmodule


// ----------------------------------------------------------------------------------------
// 12-bit register with PDP-8 console start-address reset value.
// Used only for the PC register: CLEAR/RESET must leave the machine halted with PC=0200.
// Normal PC loads still use the original active-low load_n datapath control.
// ----------------------------------------------------------------------------------------
module R12_RESET0200 (in, out, clk, reset, load_n, console_load, console_data);
	input  [11:0] in;
	output reg [11:0] out;
	input clk;
	input reset;
	input load_n;
	input console_load;
	input [11:0] console_data;

	always @(posedge clk or posedge reset) begin
		if (reset)
			out <= 12'o0200;
		else if (console_load)
			out <= console_data;
		else if (!load_n)
			out <= in;
	end
endmodule
