/* memory.v - implementation of memory external to the 9086 CPU for testing purposes

   This file is part of the 9086 project.

   Copyright (c) 2024 Efthymios Kritikos

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* This warning is because we don't use the full address bus. */
/* verilator lint_off UNUSEDSIGNAL */
module doublemem
	#(
		parameter RAM_SIZE_IN_BYTES,
		parameter ADDRESS_WIDTH=$clog2(RAM_SIZE_IN_BYTES)
	)
	(	input  [ ADDRESS_WIDTH-1 : 0 ] address,
		output [15:0] cpu_read_data,
		input  [15:0] cpu_write_data,
		input rd,
		input wr,
		input BHE,
		input cs,
		input clock
	);
/* verilator lint_on UNUSEDSIGNAL */

reg [15:0] memory [0:(RAM_SIZE_IN_BYTES/2)-1];


initial begin
`ifndef YOSYS
	string boot_code;
	if(!$value$plusargs("BOOT_CODE=%s",boot_code))begin
		$display("No boot code specified. Please add +BOOT_CODE=<path> to your vvp args");
		$finish;
	end
	$readmemh(boot_code, memory,0,(RAM_SIZE_IN_BYTES/2)-1);
`else
	//TODO: don't have it hard coded
	$readmemh("../boot_code/i2c_bootloader.stxt", memory,0,(RAM_SIZE_IN_BYTES/2)-1); // 2KiB
`endif
end


`ifdef USE_HIGH_IMPEDANCE
assign cpu_read_data[7:0]  = !address[0:0] & !rd & !cs ? memory[address[ADDRESS_WIDTH-1:1]][15:8]  : `16'hz;
assign cpu_read_data[15:8] =     !BHE      & !rd & !cs ? memory[address[ADDRESS_WIDTH-1:1]][ 7:0]  : `16'hz;
`else
assign cpu_read_data[7:0]  = memory[address[ADDRESS_WIDTH-1:1]][15:8];
assign cpu_read_data[15:8] = memory[address[ADDRESS_WIDTH-1:1]][ 7:0];
`endif


always @(posedge clock) begin
	if( cs == 0 && wr == 0) begin
		if(BHE==0)
			memory[address[ADDRESS_WIDTH-1:1]][7:0]<=cpu_write_data[15:8];
		if(address[0]==0)
			memory[address[ADDRESS_WIDTH-1:1]][15:8]<=cpu_write_data[7:0];
	end
end

endmodule
