module amiga(D);

	inout [15:0] D;
	reg [23:1] A;
	wire [23:0] Areal={A, 1'b0};
	wire [15:0] D;
	reg clock7m, CDAC;
	wire INT;
	reg READ, AS, LDS, UDS;
	reg BUSRST, CFGIN;
	wire CFGOUT;
 
	serial_board serial_board( .bus_address(A), .bus_data(D), .clock7m(clock7m), 
				.CDAC(CDAC), .INT(INT), .READ(READ), .AS(AS), .LDS(LDS),
				.UDS(UDS), .BUSRST(BUSRST), .CFGIN(CFGIN), .CFGOUT(CFGOUT) );

	initial begin
		clock7m=1'b0;
		CDAC=1'b0;
	end

	always #70 clock7m= ~clock7m;

	initial begin
		$recordvars;
		$recordvars("primitives", "drivers");
		$stop;
	end

	initial begin
		#35;
		repeat (6000) #70 CDAC= ~CDAC;
	end

	reg [15:0] cpu_data_out;
	reg processor_write;

	assign D= (processor_write) ? cpu_data_out: 16'bz;

	reg trash;

	reg [15:0] data, bus_data;

	initial begin
		BUSRST=1'b1;
		CFGIN=1'b1;
		READ=1'b0;
		AS=1'b1;
		{A, trash} = 24'hE80044;
		@(posedge clock7m);
		$display("config board before us at 80h");
		config_board(16'h0080);
		CFGIN=1'b0;
		$display("configure our board at 91h");
		config_board(16'h0091);
		$display("config board after us at 92h");
		config_board(16'h0092);
		cpu_read_bus(24'h920000, data, 1'b1, 1'b0);
		cpu_read_bus(24'h910000, data, 1'b1, 1'b0);
		cpu_write_bus(24'h800000, 16'hAAAA, 1'b0, 1'b0);
		cpu_write_bus(24'h910000, 16'hBBBB, 1'b0, 1'b0);
		cpu_write_bus(24'h920000, 16'hCCCC, 1'b0, 1'b0);
		cpu_write_bus(24'h91000A, 16'h0000, 1'b0, 1'b0);   /* soft disable */
		cpu_write_bus(24'h910002, 16'h0000, 1'b0, 1'b0);   /* clear divisor, rts, dtr */
		cpu_write_bus(24'h910004, 16'h0000, 1'b0, 1'b0);   /* set divisor to 0 (460Kbps) */
		cpu_write_bus(24'h910006, 16'h0001, 1'b0, 1'b0);   /* set rts */
		cpu_write_bus(24'h910008, 16'h0001, 1'b0, 1'b0);   /* se dtr */
		cpu_write_bus(24'h91000A, 16'h0001, 1'b0, 1'b0);   /* soft enable */
		$display("enabled at", $time);
		#100000;
		cpu_read_bus(24'h910014, data, 1'b1, 1'b0);
		cpu_read_bus(24'h910000, data, 1'b1, 1'b0);
		cpu_read_bus(24'h910000, data, 1'b1, 1'b0);
		cpu_read_bus(24'h910000, data, 1'b1, 1'b0);
		cpu_read_bus(24'h910000, data, 1'b1, 1'b0);
		cpu_read_bus(24'h910000, data, 1'b1, 1'b0);
		#120000 $finish;
	end

//	always @(clock7m) $display("databus=%h, address=%h, AS=%d, READ=%d, dsL=%d, dsH=%d, CFGIN=%d, CFGOUT=%d",
//				D, A, AS, READ, LDS, UDS, CFGIN, CFGOUT );
	task config_board;
		input [31:16] board_address;
	begin
		cpu_read_bus(24'hE80000, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80004, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80008, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80010, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80014, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80018, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE8001C, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80020, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80024, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE80028, data, 1'b1, 1'b0);
		cpu_read_bus(24'hE8002C, data, 1'b1, 1'b0);
		cpu_write_bus(24'hE80044, {board_address[31:24],8'b0}, 1'b1, 1'b0);
		cpu_write_bus(24'hE80046, {board_address[27:24],12'b0}, 1'b1, 1'b0);
		cpu_write_bus(24'hE80048, {board_address[23:16],8'b0}, 1'b1, 1'b0);
		cpu_write_bus(24'hE8004A, {board_address[19:16],12'b0}, 1'b1, 1'b0);
	end		
	endtask
			
		
	task cpu_read_bus;
		input [23:0] bus_address_in;
		output [15:0] bus_data_out;
		input upper_data_strobe_in, low_data_strobe_in;
		
	begin
		@(negedge clock7m);
		A=bus_address_in[23:1];
		READ=1'b1;
		@(posedge clock7m);
		LDS=low_data_strobe_in; 
		UDS=upper_data_strobe_in; 
		AS=1'b0;
		@(posedge clock7m);
		@(posedge clock7m);
		@(negedge clock7m);
		LDS=1'b1; 
		UDS=1'b1; 
		AS=1'b1;
		if (~low_data_strobe_in) bus_data_out[7:0]= D[7:0];
		if (~upper_data_strobe_in) bus_data_out[15:8]= D[15:8];
	end		
	endtask

	task cpu_write_bus;
		input [23:0] bus_address_in;
		input [15:0] bus_data_in;
		input upper_data_strobe_in, low_data_strobe_in;
		
	begin
		@(negedge clock7m);
		A=bus_address_in[23:1];
		@(posedge clock7m);
		READ=1'b0;
		AS=1'b0;
		cpu_data_out= bus_data_in;
		processor_write=1'b1;
		@(posedge clock7m);
		LDS=low_data_strobe_in; 
		UDS=upper_data_strobe_in; 
		@(posedge clock7m);
		@(negedge clock7m);
		LDS=1'b1; 
		UDS=1'b1; 
		AS=1'b1;
		@(posedge clock7m);
		READ=1'b1;
		processor_write=1'b0;
	end
	endtask
endmodule

module	tranceiver (rd, sd, dtr, dsr, rts, cts, cd);
	input sd, dtr, rts;
	output rd, dsr, cts, cd;

	reg rd, dsr, cts, cd;
	reg [7:0] i;

	initial begin
		rd=1'b0;
		dsr=1'b1;
		cd=1'b1;
		cts=1'b1;
	end
		
	initial begin
		rd=1'b1;
		#32000;
		#16300;
		for(i=1; i < 240; i= i+8'd3) begin
			$display("receiving %h", i);
			bytetoserial(i);
		end
		#6000;
		bytetoserial(8'd7);
	end
		

	task bytetoserial;
		input [7:0] byte;
	begin
		rd=1'b0;
		#2176;
		rd= byte[0];
		#2176;	
		rd= byte[1];
		#2176;	
		rd= byte[2];
		#2176;	
		rd= byte[3];
		#2176;	
		rd= byte[4];
		#2176;	
		rd= byte[5];
		#2176;	
		rd= byte[6];
		#2176;	
		rd= byte[7];
		#2176;	
		rd=1'b1;
		#2176;
	end
	endtask

endmodule

module serial_board( bus_address, bus_data, clock7m, CDAC, INT, READ,
			AS, LDS, UDS, BUSRST, CFGIN, CFGOUT );

	/* bus interface signals */
        input [23:1] bus_address;
        inout [15:0] bus_data;
	input clock7m, CDAC;	/* clocks */
	output INT;
	input READ;
	input AS;		/* address strobe */
	input LDS;		/* low data strobe */	
	input UDS;		/* upper data strobe */	

	/* configuration mode signals */
	input BUSRST;	/* bus reset */
	input CFGIN;	/* time to configure */
	output CFGOUT;	/* configure the next card */

	wire BUSRST, CFGIN, CFGOUT;
	wire [7:0] sram_databus;
	wire [12:0] sram_address;
	wire [15:0] bus_data;

	wire INT;

	/* almost everything happens in one big CPLD */

	wire [23:0] A= {bus_address, 1'b0};

	pads serial_chip(.bus_address(bus_address[23:1]), 
			.bus_data(bus_data), .clock7m(clock7m),
			.CDAC(CDAC), .INT(INT), .READ(READ), .AS(AS), .LDS(LDS),
			.BUSRST(BUSRST), .CFGIN(CFGIN), .CFGOUT(CFGOUT), 
			.rd(rd), .sd(sd), .dtr(dtr), .dsr(dsr), 
			.rts(rts), .cts(cts), .cd(cd), .bitclockref(bitclockref), 
			.sram_databus(sram_databus), .sram_address(sram_address), 
			.sram_oe(sram_oe),  .sram_we(sram_we));


	/* rs232 tranceiver */
	tranceiver tranceiver(	.rd(rd), .sd(sd), .dtr(dtr), .dsr(dsr), 
				.rts(rts), .cts(cts), .cd(cd));

	/* 8k SRAM contains 4k send and 4k receive buffers */ 
	sram serbuffer(	.databus(sram_databus), .address(sram_address), 
			.cs(1'b0), .oe(sram_oe),  .we(sram_we));

	/* 14.67Mhz chrystal occilator for baud rate generator */
	occilator serial_clock(bitclockref);

	/* Autoconfig ROM */
//	config_rom config_rom(	.address(bus_address[7:1]), .dataout(bus_data[3:0]), 
//				.chip_enable(1'b0), .output_enable(rom_select));
endmodule


module sram(databus, address, cs, oe,  we);
	inout [7:0] databus;
	input [12:0] address;
	input cs, oe, we;
	
	wire [12:0] address;
	wire cs, oe, we;

	reg [7:0] mem [8191:0];
	reg read;

	assign databus = (read) ? mem[address]: 8'bz;

	always @(negedge (oe | cs) ) #10 read=1'b1;

	always @(posedge (oe | cs)) #10 read=1'b0;

//	always @(posedge we ) if (~cs) #50 mem[address] = databus;
	always @(posedge we ) if (~cs) mem[address] = #5 databus;

	always @(databus or address or oe or we) $display("buffer[%h] = %h", address, mem[address]);

endmodule


module occilator(clockref);
	output clockref;
	reg clockref;

	initial clockref=1'b1;

	always #68 clockref= ~clockref;
endmodule

`include "serial_debug.v"
