// cbi.v - COSMAC Bus Interface
// (c) 2017 David R. Hunter
// Revisions:
// 	08/12/17		DH	- initial version
//		08/16/17		DH - fix bug: route memory mux to port data in
//		09/01/17		DH - reworked for multiple ROMs, remove MMIO, added write decode
//
// This module provides the multiplexing of the data busses 
// and chip selects decoding the upper 3 bits of the address (8K blocks)
// between the microprocessor and memory bus peripherals
//
// Memory Map
// 0000 - 7FFF		RAM
// 8000 - 81FF		ROM1	(VIP)
// 8200 - 83FF		ROM2	(UT4)
// 8400 - 9FFF		ROM3	(Tiny BASIC)
// A000 - BFFF		<unused>
//	C000 - DFFF		Auxiliary RAM
// E000 - FFFF		<unused>

module cbi(addr,mwr_n,rom_map,alt_rom,n0,
			cbi_to_up_data,up_to_cbi_data,
			rom1_to_cbi_data,rom2_to_cbi_data,rom3_to_cbi_data,
			ram_to_cbi_data,aux_to_cbi_data,port_to_cbi_data,
			cbi_to_ram_data,cbi_to_aux_data,cbi_to_port_data,
			ram_we,aux_we
			);
			
	input 	[6:0]addr;					// upper 7 bits of address bus
	input		mwr_n;						// microprocessor write 
	input 	rom_map;						// rom map signal
	input		alt_rom;						// boot from ROM2 instead of ROM1 (default)
	input 	n0;							// N=0 signal
	output 	[7:0]cbi_to_up_data; 	// data to microprocessor
	input 	[7:0]up_to_cbi_data;		// data from microprocessor
	input 	[7:0]rom1_to_cbi_data;	// data from ROM1
	input 	[7:0]rom2_to_cbi_data;	// data from ROM2
	input 	[7:0]rom3_to_cbi_data;	// data from ROM3
	input		[7:0]ram_to_cbi_data;	// data from RAM
	input		[7:0]aux_to_cbi_data;	// data from Aux RAM
	input 	[7:0]port_to_cbi_data;	// data from I/O port
	output	[7:0]cbi_to_ram_data;	// data to RAM
	output 	[7:0]cbi_to_aux_data;	// data to Aux RAM
	output	[7:0]cbi_to_port_data;	// data to I/O port
	output	ram_we;						// RAM write enable
	output	aux_we;						// Aux RAM write enable
	
	wire		[7:0]rom_data;				// ROM data 
	wire		[7:0]memory_data;			// memory data selected by mux
												// routed to processor and output port
	

	// set RAM write enable
	assign ram_we = ((!rom_map && (addr[6] == 1'b0)) && !mwr_n);	// RAM = 0000 - 7FFF

	// set aux RAM write enable
	assign aux_we = ((!rom_map && (addr[6:4] == 3'b110)) && !mwr_n);		// AUX = C000 - DFFF
	
	
	// multiplex the data to the microprocessor
	// use port input if N!=0, else decode the address from memory
	
	assign cbi_to_up_data = (!n0) ? port_to_cbi_data : memory_data;
	
	// if rom_map and alt_rom = 0, boot from ROM1
	// if rom_map and alt_rom = 1, boot from ROM2
	// select ROM1 if address 8000-81FF
	// select ROM2 if address 8200-83FF
	// select ROM3 if address >= 8400
	assign rom_data = ((rom_map && !alt_rom) || (addr == 7'b1000000)) ? rom1_to_cbi_data :
							((rom_map &&  alt_rom) || (addr == 7'b1000001)) ? rom2_to_cbi_data : rom3_to_cbi_data;
	
	
	assign memory_data = 	(rom_map || addr[6:4] == 3'b100) ? rom_data : 								
									(addr[6:4] == 3'b000) 				? ram_to_cbi_data :
									(addr[6:4] == 3'b110)  				? aux_to_cbi_data : 8'hFF;
	
	// multiplex the data to the read/write memory (RAM/AUX)
	assign cbi_to_ram_data = n0 ? up_to_cbi_data : port_to_cbi_data;
	assign cbi_to_aux_data = n0 ? up_to_cbi_data : port_to_cbi_data;
	
	// output data comes only from the processor
	assign cbi_to_port_data = memory_data;
	
			
endmodule
