// MicroVIP.v
// (c) 2017  David R. Hunter
//
// FPGA:		Intel (Altera) Cyclone II 	2C5T144C8
// Revisions:
//		0		08/11/17	 	DH	- initial version with ROM only
//		1		08/12/17		DH	- added bus multiplexer and RAMs
//		2		08/13/17		DH - add UT4 serial RX (~EF4_n)/TX (~Q)  (CDP18S020 equivalent)
//		3		08/16/17		DH - added port mux and ports, 
//										changed memory map to allow for more ROM later
//		4		08/20/17		DH - change serial RX to ~EF2, GPIO strobe to EF4 (like VIP)
//										EF2 was used as tape in for VIP which isn't needed here
//										add speaker tone generator
//		5		08/27/17		DH - add PIXIE graphics 
//		6		09/01/17		DH - changed memory map to have multiple ROMs, removed MMIO
//		7		09/02/17		DH	- added SPI for serial flash communication
//

//`define SIM

// This is an implementation of the COSMAC VIP in an FPGA
// It is based on the original VIP computer from 1977.
// Celebrating the 40th anniversary of the RCA VIP!
//

// Memory Map
// 0000 - 0FFF		RAM (4K)
// 8000 - 81FF		ROM1 (512)
// 8200 - 83FF		ROM2 (512)
// 8400 - 9FFF		ROM3 (7K)
//	A000 - BFFF		<unused>
//	C000 - C3FF		Auxiliary RAM (1K)
// D000 - FFFF		<unused>

// I/O Port Map		[] = future option
//		#	OUT				IN
// 	1 	video off		video on
//		2	keypad			[ASCII Keyboard]
//		3	output port		input port
//		4	[I2C out]		[I2C in]
//		5	control reg		[UART status]
//		6	[UART txd]		[UART rxd]
//		7	SPI out			SPI in				


// MicroVIP top level
module MicroVIP(inclk0_sig,led_1_n,led_2_n,led_3_n,ext_por_n,
		run_sw,q_led,uart_txd,ef_n,
		keypad_out,gpio_out,gpio_in,gpio_out_stb,gpio_out_stb_n,
		flash_miso,flash_mosi,flash_sclk,flash_cs_n,flash_wp_n,f_led,
		pbtn,speaker,sync_n,video
		);

	input  inclk0_sig;					// on board 50MHz clock
	output led_1_n,led_2_n,led_3_n;	// on board LEDs  (D2,D4,D5)
	input  ext_por_n;						// power on reset input
  
	input  run_sw;							// run switch  (1 = RUN, 0 = reset)
	output q_led;
	output uart_txd;						// serial out
  
	input  [4:2]ef_n;						// external flag inputs
												// ef_n[4] = input port strobe
												// ef_n[3] = keypad input / ASCII keyboard strobe
												// ef_n[2] = serial in
												// ef_n[1] is not an external input (used by Pixie)	
												
	output [15:0]keypad_out;			// keypad switch connections
	
	output [7:0]gpio_out;				// GPIO ports
	input	 [7:0]gpio_in;
	output gpio_out_stb;					// active high strobe for GPIO output port
	output gpio_out_stb_n;				// active low strobe for GPIO output port
	
	input	 flash_miso;					// serial flash out
	output flash_mosi;					// serial flash in
	output flash_sclk;					// serial flash clock
	output flash_cs_n;					// serial flash chip select
	output flash_wp_n;					// serial flash write protect
	output f_led;							// storage LED

	input	 pbtn;							// FPGA card pushbutton (to select alternate boot ROM)
	output speaker;						// speaker output
	output sync_n;							// PIXIE sync output
	output video;							// PIXIE video output

	// PIXIE signals
	wire pixie_on;							// enable PIXIE graphics
	wire pixie_off;						// disable PIXIE graphics
 
  
    // control and bus signals
	wire  areset_sig;						// PLL reset
	wire  locked_sig;						// PLL lock
	reg   reset_n_q1;						// intermediate reset signal
	
	wire 	n0;								// indicate N=0

	wire  [7:0]rom1_dout;				// ROM1 data out
	wire  [7:0]rom2_dout;				// ROM2 data out

	reg	[3:0]map_cnt;					// ROM map counter
	wire	rom_map;							// ROM map signal
	wire	alt_rom;							// Boot from ROM2 instead of ROM1
	
	wire	[7:0]ram_dout;					// RAM data out
	wire	[7:0]ram_din;					// RAM data in
	wire 	ram_cs;							// RAM chip select
	wire	ram_we;							// RAM write enable

	wire	[7:0]aux_dout;					// Aux RAM data out
	wire	[7:0]aux_din;					// Aux RAM data in
	wire 	aux_cs;							// Aux RAM chip select
	wire	aux_we;							// Aux RAM write enable
	
	
	// port signals
	wire	keypad_stb;						// Hex keypad strobe (port 2)
	wire 	output_stb;						// output port strobe (port 3)
	wire 	control_stb;					// control register strobe (port 5)
	wire	spi_stb;							// SPI load strobe (port 7)
	wire 	[3:0]keypad_select;			// Key switch select
	wire	[7:0]port_dout;				// Port data out
	wire	[7:0]port_din;					// Port data in
	reg	[7:0]out_reg;					// GPIO output register
	wire 	[7:0]out_data3;				// GPIO output port data
	reg	[7:0]control_reg;				// control register (port 5)
	wire	[7:0]control_reg_data;		// control register data from PMUX
	wire 	[7:0]spi_data_in;				// SPI receive data
	wire 	[7:0]spi_data_out;			// SPI transmit data

	wire	tone_out;						// tone generator output
	
	// internal clock signals
	wire clock;								// internal FPGA clock
	wire pulse_sys;						// processor clock pulse 1.76MHz * 2

	// 1802 signals
	reg  SYSCLK;							// processor input clock 1.76 MHz
	reg CLEAR_N;							// processor clear (RUN or POR)
	wire WAIT_N;							// processor wait
	wire DMAI_N;							// DMA is used for load function
	wire DMAO_N,INT_N;					// currently unused
	wire Q;									// Q flip-flop output
	wire EF1_N;								// external flag inputs
	wire EF2_N;
	wire EF3_N;
	wire EF4_N;
	wire XTAL_N;							// PIXIE clock
	wire TPA,TPB,MWR_N,MRD_N;			// output control signals
	wire [2:0]N;							// I/O address
	wire [7:0]DATA_OUT;					// processor data out
	wire [7:0]MA;							// memory address
	wire [7:0]MA1;
	wire [1:0]SC;							// state code
	wire OE_N;								// output enable signal
	wire [2:0]CYCLE;						// for debugging
	wire [7:0]DATA_IN;					// processor data in
 
   // clock divisors
`ifdef SIM
	parameter SYSTEM_CLK_BITS = 3;	// number of bits for counter = int(log(div)/log(2)) + 1
	parameter SYSTEM_CLK_DIV = 3;		// division ratio of master clock to processor clock

	parameter BAUD_CLK_BITS = 3;
	parameter BAUD_CLK_DIV = 6;


`else	// normal clock divisors  (PLL Output = 137.5 MHz)
	parameter SYSTEM_CLK_BITS = 7;	// number of bits for counter = int(log(div*2)/log(2)) + 1
	parameter SYSTEM_CLK_DIV = 39;	// division ratio / 2 of master clock used to make the
                                    // processor clock (1.7628 MHz) which is a square wave												
 											
	parameter BAUD_CLK_BITS = 7;
	parameter BAUD_CLK_DIV = 75;		// division ratio to get 16x 115200 baud clock 
												// (1.83333 MHz) (-0.54% error)
`endif

	// set LEDs
	// led_x_n are on the FPGA module, note LEDs are on when output is low
	assign led_1_n 		= ~locked_sig;	// D2 LED
	assign led_2_n 		= ~TPA;			// D4 LED
	assign led_3_n 		= alt_rom;		// D5 LED
	assign q_led			= Q;				// main board Q LED
	assign f_led 			= (control_reg[1:0] == 2'b11) ? Q : 1'b0;		// storage LED = !flash_cs
	
	//*** generate clocks
`ifdef SIM
	assign clock = inclk0_sig;
	assign locked_sig = 1'b1;
`else

	// 137.5 MHz PLL - megafunction
	pll_clock	MCLK
	(
		.areset			(areset_sig),
		.inclk0			(inclk0_sig),
		.c0				(clock),
		.locked			(locked_sig)
	);
`endif

	// processor clock divider
	defparam X1.Nbits = SYSTEM_CLK_BITS;
	defparam X1.Divisor = SYSTEM_CLK_DIV;
	clockgen X1
	(
		.reset_n			(ext_por_n),
		.enable			(1'b1),				// always enabled
		.clkin			(clock),
		.clkout			(),
		.pulse			(pulse_sys)			// pulse output at 2x processor clock
	);
	
	// create the processor clock
	always @(posedge clock)
	begin
		if (!ext_por_n)
			SYSCLK <= 0;
		else if (pulse_sys)
			SYSCLK <= ~SYSCLK;
	end
	
	// synchronize RUN switch
	always @(posedge inclk0_sig)
	begin
		CLEAR_N <= run_sw & ext_por_n;
	end
	
	// ROM mapper
	// Enable ROM at address 000x for first 16 bus cycles (8 fetch/execute)
	always @(posedge TPB or negedge CLEAR_N)
	begin
		if (!CLEAR_N)
				map_cnt = 4'd15;
		else if (map_cnt > 4'd0)
				map_cnt = map_cnt - 4'd1;
	end
	
	assign rom_map = (map_cnt > 4'd0);
	
	assign alt_rom = !pbtn;		// use push button to select the alternate boot ROM
	
	//*** interconnects
	assign WAIT_N = 1'b1;		// "tied off" signals
	assign DMAI_N = 1'b1;
	
	assign EF2_N = !ef_n[2];	// invert EF2 for serial RXD
	assign EF3_N = ef_n[3];		// keypad / keyboard strobe
	assign EF4_N = ef_n[4];		// GPIO input strobe

	// latch GPIO output only when port 3 is addressed
	// but hold before and after the strobe
	always @(posedge clock)
	begin
		if (!CLEAR_N)
			out_reg <= 8'h00;
		else if ((N == 3'b011) && (!MRD_N))
			out_reg <= out_data3;
	end
	
	assign gpio_out = out_reg;
	
	//*** control register
	// bit 0,1:	Q mux					00 = tone (VIP)
	//										01 = serial (UT4)
	//										10 = GPIO out strobe
	//										11 = Flash SPI CS
	// bit 2: 	Tone Disable		0 = tone enabled  1 = tone disabled
	// bit 3:	UART pins			0 = Q/EF2  1 = UART (future) 	
	//	bit 4:	Flash WP				0 = WP off 1 = WP on
	// bit 5:	<open>	
	// bit 6:	<open>
	// bit 7: 	<open>
	
	// control register latch
	always @(posedge control_stb or negedge ext_por_n)
	begin
		if (!ext_por_n)
			control_reg <= 8'h00;	// clear on power up
		else
			control_reg <= control_reg_data;
	end
	
	// set configuration based on control latch

	// set speaker output if Q mux is in VIP mode and tone is not disabled
	assign speaker = (control_reg[2:0] == 3'b000) ? tone_out : 1'b0;
	
	// set uart output
	assign uart_txd = (control_reg[3] == 1'b1) 		? 1'b0 	:		// select UART [future]
							(control_reg[1:0] == 2'b01) 	? !Q 		: 1'b0;
	
	// GPIO output strobes (both active high and active low)
	// use output port strobe unless Q is set to be the strobe
	assign gpio_out_stb = (control_reg[1:0] != 2'b10) ? output_stb : Q;
	assign gpio_out_stb_n = !gpio_out_stb;
	
	// SPI signals
	assign flash_wp_n = !control_reg[4];
	assign flash_cs_n = (control_reg[1:0] == 2'b11) ? !Q : 1'b1;
	
	
   //*** 1802 processor connections
	cdp1802 U1
	(
		.clk					(SYSCLK),	// processor clock
		.clr_n				(CLEAR_N),
		.wait_n				(WAIT_N),
		.dmai_n				(DMAI_N),
		.dmao_n				(DMAO_N),
		.int_n				(INT_N),
		.ef1_n				(EF1_N),
		.ef2_n				(EF2_N),
		.ef3_n				(EF3_N),
		.ef4_n				(EF4_N),
		.data_in				(DATA_IN),
		.xtal_n				(XTAL_N),	// clock out to PIXIE
		.tpa					(TPA),
		.tpb					(TPB),
		.mwr_n				(MWR_N),
		.mrd_n				(MRD_N),
		.sc					(SC),
		.q						(Q),
		.n_out				(N),
		.data_out			(DATA_OUT),
		.ma					(MA),    
		.ma1					(MA1),	// latched upper address
		.oe_n					(OE_N),	// external tri-state control
		.cycle_out			(CYCLE)
	);

	//*** 512 byte VIP ROM (0x8000)
	sync_rom_vip  U2A
	(
		.data					(8'h00),
		.addr					({MA1[0], MA}),
		.clk					(SYSCLK),
		.q						(rom1_dout)
	);

	//*** 512 byte UT4 ROM (0x8200)
	sync_rom_ut4  U2B
	(
		.data					(8'h00),
		.addr					({MA1[0], MA}),
		.clk					(SYSCLK),
		.q						(rom2_dout)
	);

	//*** 1024 byte Auxiliary RAM (0xC000)
	sync_ram_1024  U3
	(
		.data					(aux_din),
		.addr					({MA1[1:0], MA}),
		.we					(aux_we),
		.clk					(SYSCLK),
		.q						(aux_dout)
	);

	//*** 4k byte RAM (0x0000)
	sync_ram  U4
	(
		.data					(ram_din),
		.addr					({MA1[3:0], MA}),
		.we					(ram_we),
		.clk					(SYSCLK),
		.q						(ram_dout)
	);

	// bus multiplexer
	cbi	BMUX
	(
		.addr					(MA1[7:1]),	// A15-A9
		.mwr_n				(MWR_N),
		.rom_map				(rom_map),
		.alt_rom				(alt_rom),
		.n0					(n0),
		.cbi_to_up_data	(DATA_IN),
		.up_to_cbi_data	(DATA_OUT),
		.rom1_to_cbi_data	(rom1_dout),
		.rom2_to_cbi_data	(rom2_dout),
		.rom3_to_cbi_data	(8'hEE),		// unused for now
		.ram_to_cbi_data	(ram_dout),
		.aux_to_cbi_data	(aux_dout),
		.port_to_cbi_data	(port_dout),
		.cbi_to_ram_data	(ram_din),
		.cbi_to_aux_data	(aux_din),
		.cbi_to_port_data	(port_din),
		.ram_we				(ram_we),
		.aux_we				(aux_we)
	);
	
	// port interface
	ports	PMUX
	(
		.n						(N),
		.n0					(n0),
		.mrd_n				(MRD_N),
		.tpb					(TPB),
		.din					(port_din),
		.dout					(port_dout),
		.in_enb1				(pixie_on),
		.out_stb1			(pixie_off),
		.out_stb2			(keypad_stb),
		.out_stb3			(output_stb),
		.out_stb4			(),
		.out_stb5			(control_stb),
		.out_stb6			(),
		.out_stb7			(spi_stb),
		.out_data2			(keypad_select),
		.out_data3			(out_data3),
		.out_data4			(),
		.out_data5			(control_reg_data),
		.out_data6			(),
		.out_data7			(spi_data_out),
		.in_data2			(8'h22),
		.in_data3			(gpio_in),
		.in_data4			(8'h44),
		.in_data5			(8'h55),
		.in_data6			(8'h66),
		.in_data7			(spi_data_in)		
	);
	
	// hex keypad interface, one output per switch
	keypad SWITCHES
	(
		.stb					(keypad_stb),
		.select				(keypad_select),
		.switch				(keypad_out)
	);
	
	// tone generator for the speaker ~850Hz
	tone TONEGEN
	(
		.clock				(SYSCLK),
		.enable				(Q),
		.tone_out			(tone_out)
	);
	
	//*** PIXIE (CDP1861) graphics module (port 1)
	//-- it's not a VIP without PIXIE graphics!
	pixie	PIXIE
	(
		.clock_n				(XTAL_N),
		.reset_n				(CLEAR_N),
		.sc					(SC),
		.tpa					(TPA),
		.tpb					(TPB),
		.disp_on				(pixie_on),
		.disp_off			(pixie_off),
		.di					(DATA_IN),
		.clear_n				(),			// clear output is not used
		.int_n				(INT_N),
		.efx_n				(EF1_N),
		.dmao_n				(DMAO_N),
		.comp_sync_n		(sync_n),
		.video				(video),
		.vsync_out			()				// for debugging
	);
	
	// serial flash SPI interface
	// uses Q as CS_N if control register set properly
	spi FLASH
	(
		.reset_n				(CLEAR_N),
		.clk4x				(inclk0_sig), // use input 50 MHz for 4x clock
//		.clk4x				(clock),		// use PLL output for 4x clock
		.load					(spi_stb),
		.ready				(),			// running way faster than micro, so not needed
		.din					(spi_data_out),
		.dout					(spi_data_in),
		.sdo					(flash_mosi),
		.sdi					(flash_miso),
		.sck					(flash_sclk)
	);
	
endmodule	