`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    10:34:42 11/25/2006 
// Design Name: 
// Module Name:    gldata 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////


module mem_sync_CPU (
addr,
data,
dataout,
en,
wen,
clk,
rst
);

input[31:0] addr;

input[31:0] data;

output[31:0] dataout;
reg[31:0] dataout;

input[3:0] en;

input[3:0] wen;

input clk;

input rst;

`define memsize (96*1024 - 1)

reg[31:0] mem[0:`memsize];

reg[7:0] mem0[0:`memsize];
reg[7:0] mem1[0:`memsize];
reg[7:0] mem2[0:`memsize];
reg[7:0] mem3[0:`memsize];


reg[3:0] en_r;


// assign data = (~(|wen) & (|en_r)) ? dataout : 32'bz;


reg[7:0] val0;
reg[7:0] val1;
reg[7:0] val2;
reg[7:0] val3;


always @(posedge clk)
	begin
		dataout <= {mem3[addr[16:2]],mem2[addr[16:2]],mem1[addr[16:2]],mem0[addr[16:2]]};
		if (|wen)
			begin
				if (wen[0])
					mem0[addr[16:2]] <= data[7:0];
				if (wen[1])
					mem1[addr[16:2]] <= data[15:8];
				if (wen[2])
					mem2[addr[16:2]] <= data[23:16];
				if (wen[3])
					mem3[addr[16:2]] <=  data[31:24];
				en_r <= en;
			end
		else
			begin
//				dataout <= {mem3[addr[16:2]],mem2[addr[16:2]],mem1[addr[16:2]],mem0[addr[16:2]]};
				en_r <= en;
			end
	end

integer i;
reg[31:0] val;

initial begin
//	$readmemh("../lisp/micasm/main-mem-dump.txt", mem);
	$readmemh("../lisp/micasm/akt-test.dump", mem);
	#1	
	for (i = 0; i < `memsize; i = i + 1) begin
		val = mem[i];
		mem0[i] = val[7:0];
		mem1[i] = val[15:8];
		mem2[i] = val[23:16];
		mem3[i] = val[31:24];
	end
end
/*
initial begin
	#499990
	for (i = 0; i < `memsize; i = i + 1) begin
		mem[i] = {mem3[i],mem2[i],mem1[i],mem0[i]}; 
	end
	$writememh("mem-result-dump.txt", mem);


end
*/
endmodule

module mem_sync_VGA (
ena, dia, doa, addra, wea, ssra,
								
enb, dob, addrb, 
clka, clkb);

// port A


input[31:0] addra;

input[31:0] dia;

output[31:0] doa;

input[3:0] ena;

input[3:0] wea;

input[3:0] ssra;

// port B

input[3:0] enb;

output[31:0] dob;

input[31:0] addrb;

// clocks

input clka, clkb;


`define memsize (2*1024 - 1)

reg[31:0] mem[0:`memsize];

reg[7:0] mem0[0:`memsize];
reg[7:0] mem1[0:`memsize];
reg[7:0] mem2[0:`memsize];
reg[7:0] mem3[0:`memsize];



reg[31:0] dataouta;
reg[31:0] dataoutb;

reg[3:0] ena_r;
reg[3:0] enb_r;

always @(posedge clkb)
	enb_r <= enb;

always @(posedge clkb)
	ena_r <= ena;



assign dob = (|enb_r) ? dataoutb: 32'bz;

assign doa = (|ena_r) ? dataouta: 32'bz;


reg[7:0] val0;
reg[7:0] val1;
reg[7:0] val2;
reg[7:0] val3;


always @(posedge clka)
	begin
		if (|wea)
			begin
				if (wea[0])
					begin
						mem0[addra[16:2]] <= dia[7:0];
//						$put_char_out(addra[16:2], dia[7:0],2'b00);
						$put_char_out(addra[16:4], dia[7:0],addra[3:2]); // necessary correction for new VGA scheme
//						$display("char =%h", dia[7:0]);
					end
				if (wea[1])
					begin
						mem1[addra[16:2]] <= dia[15:8];
						//$put_char_out(addra[16:2], dia[15:8],2'b01);
					end
				if (wea[2])
					begin
						mem2[addra[16:2]] <= dia[23:16];
						//$put_char_out(addra[16:2], dia[23:16],2'b10);
					end
				if (wea[3])
					begin
						mem3[addra[16:2]] <=  dia[31:24];
						//$put_char_out(addra[16:2], dia[31:24],2'b11);
					end
			end
		else
			begin
				dataouta <= {mem3[addra[16:2]],mem2[addra[16:2]],mem1[addra[16:2]],mem0[addra[16:2]]};
			end
	end

always @(posedge clkb)
	begin
			begin
				dataoutb <= {mem3[addrb[16:2]],mem2[addrb[16:2]],mem1[addrb[16:2]],mem0[addrb[16:2]]};
			end
	end

integer i;
reg[31:0] val;


/*
initial begin
//	$readmemh("main-mem-dump.txt", mem);
	$readmemh("akt-test.dump", mem);
	#1	
	for (i = 0; i < `memsize; i = i + 1) begin
		val = mem[i];
		mem0[i] = val[7:0];
		mem1[i] = val[15:8];
		mem2[i] = val[23:16];
		mem3[i] = val[31:24];
	end
end
*/

/*
initial begin
	#499990
	for (i = 0; i < `memsize; i = i + 1) begin
		mem[i] = {mem3[i],mem2[i],mem1[i],mem0[i]}; 
	end
	$writememh("mem-result-dump.txt", mem);


end
*/

endmodule


module sram_ISSI ( addr, data_io, 
											ce, oe, we,
											ub, lb );
											
input[17:0] addr;

inout[15:0] data_io;

input ce, oe, we, ub, lb;


`define memsize (1 << 17)

reg[7:0] mem0[0:`memsize - 1];
reg[7:0] mem1[0:`memsize - 1];

reg[7:0] dataout_h, dataout_l;

assign data_io = (~ce & ~oe & we ) ? { dataout_h, dataout_l } : 16'bz;

always @(ub or addr)
	begin
		if (~ub)
			dataout_h = mem1[addr];
		else
			dataout_h = 8'bz;
	end

always @(lb or addr)
	begin
		if (~lb)
			dataout_l = mem0[addr];
		else
			dataout_l = 8'bz;
	end

always @(addr or data_io or ce or we or ub or lb)
	begin
		if (~ce & ~we & ~ub)
			begin
				//$display ( "upper byte: addr = %h data_io = %h\n we = %h", addr, data_io[15:8], we );
				mem1[addr] = data_io[15:8];
			end
		if (~ce & ~we & ~lb)
			begin
				//$display ( "lower byte: addr = %h data_io = %h\n we = %h", addr, data_io[7:0], we );
				mem0[addr] = data_io[7:0];
			end
	end




endmodule



module mem_sync_dual ( ena, dia, doa, addra, wea, ssra, clka);


input[31:0] dia;

output[31:0] doa;

reg[31:0] doa;

input[3:0] ena;
input[3:0] wea;

input[3:0] ssra;

input[12:0] addra;

wire[10:0] addr = addra[12:2];

reg[10:0] addr_o;

input clka;

always @(posedge clka)
	begin
		addr_o = addr;
	end



`define memsize (2*1024-1)

	

reg[7:0] mem0[0:`memsize];
reg[7:0] mem1[0:`memsize];
reg[7:0] mem2[0:`memsize];
reg[7:0] mem3[0:`memsize];

wire woka0 = ena[0] & wea[0];
wire woka1 = ena[1] & wea[1];
wire woka2 = ena[2] & wea[2];
wire woka3 = ena[3] & wea[3];

reg[7:0] doa0;
reg[7:0] doa1;
reg[7:0] doa2;
reg[7:0] doa3;


always @(posedge clka)
	begin
		if (woka0)
			mem0[addr] = dia[7:0];
		if (woka1)
			mem1[addr] = dia[15:8];
		if (woka2)
			mem2[addr] = dia[23:16];
		if (woka3)
			mem3[addr] = dia[31:24];	
	end

always @(addr_o)
	begin
		if (ena[0])
			doa0 = mem0[addr_o];
		else
			doa0 = 8'bz;
		if (ena[1])
			doa1 = mem1[addr_o];
		else
			doa1 = 8'bz;
		if (ena[2])
			doa2 = mem2[addr_o];
		else
			doa2 = 8'bz;
		if (ena[3])
			doa3 = mem3[addr_o];
		else
			doa3 = 8'bz;
	end

always @(doa0, doa1, doa2, doa3)
	begin
		doa = { doa3, doa2, doa1, doa0 };
	end

endmodule

