module pads(	bus_address, bus_data, clock7m,
		CDAC, INT, READ, AS, LDS, BUSRST, CFGIN, CFGOUT,
		rd, sd, dtr, dsr, rts, cts, cd, bitclockref,
		sram_databus, sram_address, sram_oe,  sram_we
		/* temporary debug signals */
//		,RST,rise, risebar, fall, fallbar
		);

	/* 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 */	
        wire [23:1] bus_address;
        wire [15:0] bus_data;
	wire clock7m, CDAC;	/* clocks */
	wire INT;
	wire READ;
	wire AS;		/* address strobe */
	wire LDS;		/* low data strobe */	

	/* configuration mode signals */
	input BUSRST;	/* bus reset */
	input CFGIN;	/* time to configure */
	output CFGOUT;	/* configure the next card */
//	output rom_select;	/* enable external configuration ROM */
	wire BUSRST, CFGIN, CFGOUT, rom_select;

	/* RS232C signals leading to tranceiver */
	input rd, dsr, cts, cd; 
	output sd, dtr, rts; 
	wire rd, dsr, cts, cd, sd, dtr, rts;

	/* reference clock for baud rate generator */
	input bitclockref;
	wire bitclockref;

	/* signals leading to external buffer SRAM */
	inout [7:0] sram_databus;
	output [12:0] sram_address;
	output sram_oe, sram_we;
	
	wire write_bus;
/* temporary debug signals */
/*	input RST;
	wire RST;
	output rise, risebar;
	output fall, fallbar;

	reg rise, risebar;
	reg fall, fallbar;

	always @(posedge RST or posedge write_bus)
		if (write_bus) begin
			rise=0;
			risebar=1;
		end else begin
			rise=1;
			risebar=0;
		end
	
	always @(negedge RST or posedge write_bus)
		if (write_bus) begin
			fall=0;
			fallbar=1;
		end else begin
			fall=1;
			fallbar=0;
		end
*/		
///////////////////////////////////////

	wire [11:0] recv_byte_count, send_byte_count;
	wire [7:0] sram_write_latch, byte_in, byte_out, divisor;
	wire [7:0] cpu_data_in, cpu_data_out, serial_in, serial_dataout;
	wire [3:0] rom_out;

	/* handles autoconfig and card selection */
	config config(	.BUSRST(BUSRST), .CFGIN(CFGIN), .CFGOUT(CFGOUT), 
			.READ(READ), .AS(AS), .low_data_strobe(LDS), 
			.address(bus_address),
			.data_bus8(bus_data[15:8]), .card_select(card_select), 
			.enable(enable), .hard_enable(hard_enable), 
			.soft_enable(soft_enable), .rom_select(rom_select), 
			.rom_out(rom_out), .clock7m(clock7m) );

	clockgen clockgen(	.clock16x(clock16x), .clock1x(clock1x), 
				.clock10(clock10), .watchdog(watchdog), 
				.clockref(bitclockref), .divisor(divisor), 
				.enable(enable));


	wire [15:0] bus_data_out;
//	assign bus_data= (write_bus) ? bus_data_out: 16'bz;
//	assign bus_data[15:4]=	(write_bus) ? bus_data_out[15:4]: 12'bz;
//	assign bus_data[3:0]=	(rom_select) ? ~rom_out: 
//				(write_bus) ? bus_data_out[3:0]: 4'bz;
	assign bus_data[15:12]=	(rom_select) ? rom_out: 
				(write_bus) ? bus_data_out[15:12]: 4'bz;
	assign bus_data[11:0]=	(write_bus) ? bus_data_out[11:0]: 12'bz;

	wire [9:0] bus_data_in= {bus_data[12], bus_data[11], bus_data[7:0]};

	/* All access from the cpu happens here */
	cpu_access cpu_access (	.bus_data_in(bus_data_in), .bus_data_out(bus_data_out),
			.clock7m(clock7m), .write_bus(write_bus), 
			.card_select(card_select), .bus_read_write(READ), .data_strobe(LDS),
			.f_select(bus_address[4:1]), .serial_data_in(cpu_data_in), 
			.serial_data_out(cpu_data_out), .read(cpu_read_buffer), 
			.write(cpu_write_buffer), .send_byte_count(send_byte_count),
			.receive_byte_count(recv_byte_count), .cts(cts), .cd(cd), 
			.dsr(dsr), .rts(rts), .dtr(dtr), .divisor(divisor), 
			.hard_enable(hard_enable), .soft_enable(soft_enable), .charmode(charmode));

	assign sram_databus= (sram_oe) ? sram_write_latch: 8'bz;

	/* controls access to the external SRAM buffer */
        buffer buffer( .cpu_dataout(cpu_data_in), .serial_dataout(serial_dataout),
                .CPUin(cpu_data_out), .serial_in(serial_in),
                .cpu_read_req(cpu_read_buffer), .cpu_write_req(cpu_write_buffer),
                .serial_read_req(serial_read_buffer), 
                .serial_write_req(serial_write_buffer),
                .serial_read_done(serial_read_done),
                .sram_data(sram_databus), .sram_write_latch(sram_write_latch),
		.sram_addr(sram_address), 
                .sram_output_enable(sram_oe), .sram_write_enable(sram_we), 
		.recv_bytecount(recv_byte_count), .send_bytecount(send_byte_count),
		.clock7m(clock7m), .CDAC(CDAC), .enable(enable) );

	/* the high level data sender. Transmits via low level serial transmitter */
        senddata senddata(       .datain(serial_dataout),
                        .read_buffer(serial_read_buffer), 
                        .read_done_req(serial_read_done),
                        .clock10(clock10), .clock7m(clock7m),
                        .bytecount(send_byte_count), .byte(byte_out), .ready(ready),
                        .enable(enable) );

	/* low level serial transmitter */
	shiftout shiftout(.byte(byte_out), .ready_req(ready), .clockref(bitclockref), 
				.clock1x(clock1x), .sd(sd), .enable(enable));

	wire interupt;

	assign INT= (interupt) ? 1'b0: 1'bz;

	/* The high level data receiver.  Recieves via low level serial receiver */
	recvdata recvdata(	.dataout(serial_in),
			.write_buffer(serial_write_buffer),
			.clock7m(clock7m), .charmode(charmode), .interupt(interupt),
			.interupt_ack(cpu_read_buffer), .bytecount(recv_byte_count),
			.remove_byte(cpu_read_buffer), .cd(cd), .watchdog(watchdog), 
			.byte(byte_in), .ready_req(byte_received), .enable(enable) ); 

	/* low level serial receiver */
	shiftin shiftin(.byteout(byte_in), .ready(byte_received), .clock16x(clock16x), 
			.clockref(bitclockref), .rd(rd), .enable(enable));

endmodule

module shiftout(byte, ready_req, clockref, clock1x, sd, enable);
	input [7:0] byte;
	input ready_req;
	
	input clockref, clock1x;
	output sd;
	input enable;
	wire [7:0] byte;

	wire clock1x;	/* 1x send clock */
	reg sd;

	reg [3:0] bitcount;
	reg stop;
	
	reg ready_ack, ready_req_reg;
	wire ready= ready_req_reg ^ ready_ack;

	always @(negedge clockref) 
		ready_req_reg= ready_req;
		
/*	initial begin
		bitcount= 4'd12;
		ready_ack= 1'b0;
	end
*/
	always @(posedge clockref)
	if (clock1x & enable)
		case ( bitcount )
			4'd0: begin 
				ready_ack= ~ready_ack;  /* reset for next byte */
				sd = byte[0];
				bitcount = 4'd1;
			   end
			4'd1: begin 
				sd = byte[1];
				bitcount=4'd2;
			   end
			4'd2: begin 
				sd = byte[2];
				bitcount=4'd3;
			   end
			4'd3: begin 
				sd = byte[3];
				bitcount=4'd4;
			   end
			4'd4: begin 
				sd = byte[4];
				bitcount=4'd5;
			   end
			4'd5: begin 
				sd = byte[5];
				bitcount=4'd6;
			   end
			4'd6: begin 
				sd = byte[6];
				bitcount=4'd7;
			   end
			4'd7: begin 
				sd = byte[7];
				bitcount=4'd8;
				stop=1'b1; /* send at least one stop bit */
			   end
			default: if(stop | ~ready) begin
					sd=1'b1;
					stop=1'b0;
				 end
				 else begin
					sd=1'b0;
					bitcount=4'd0;
				end
		endcase
	else if( ~enable ) begin
		/* initialize */
		sd=1'b1;
		bitcount=4'd8;
		stop=1'b1;
	end

endmodule

/* this module generates all derived clocks */

module clockgen(clock16x, clock1x, clock10, watchdog, clockref, divisor, enable);
	output clock16x;	/* 16x receive clock */
	output clock1x;	/* 1x transmit clock */
	output clock10;	/* byte clock = 1x clock / 10 */
	output watchdog; /* slow clock prevents stalls if packets are incomplete */
	input clockref; /* 7.37Mhz reference clock = 16x clock for 460kbps */
	input [7:0] divisor;	/* used to generate baud rates from reference clock */
	input enable;	/* enable/disable clocks */

	wire clock16x;
	reg clock1x, clock10, watchdog;

	reg [7:0] count16x, count16x_next;
	reg [3:0] count1x, count1x_next;
	reg [3:0] count10, count10_next;

	reg [14:0] watchcount, watchcount_next;
/*	initial begin
		#10;
		clock1x=1'b0;
		clock10=1'b0;
		watchdog=1'b0;
		count16x=8'b1;
		count1x=4'b0;
		count10=4'b0;
		watchcount=15'd5;
		clock16x_pos=1'b0;
		count10=4'd10;
	end
*/		
	wire clockref;
	wire [7:0] divisor;

	assign clock16x= (count16x == 8'b0) ? 1'b1: 1'b0;

	always @(posedge clockref) 
    		if (enable) count16x= count16x_next;
		else count16x= divisor;		

	always @(count16x or divisor)
		if (count16x == 8'b0) count16x_next= divisor; 
		else count16x_next= count16x -1;
	
	always @(negedge clockref)	
		if (enable & clock16x) count1x = #5 count1x_next;

	always @(negedge clockref)
		if (enable & clock16x & (count1x == 4'b0) ) clock1x= #5 1'b1;
		else clock1x= #5 1'b0;

	always @(enable or count1x)
		if (enable) count1x_next = #5 count1x - 1;
		else count1x_next= 4'd15;

	always @(posedge clockref)
		if (clock1x & enable) count10 = count10_next;

	always @(posedge clockref)
		if (enable & clock1x & (count10 == 4'b0) ) clock10=1'b1;
		else clock10=1'b0;

	always @(enable or count10)
		if (enable & count10 != 4'b0) count10_next = count10-1;
		else count10_next=4'd9;
	
	always @(posedge clockref)
	if (enable) watchcount = watchcount_next;
	else watchcount= 15'b0;
	  
	always @(watchcount or watchdog) begin
		watchcount_next= watchcount -1;
		if (watchcount == 0) watchdog = 1'b1;
		else watchdog= 1'b0;
	end

endmodule

module senddata(datain, read_buffer, read_done_req, 
		clock10, clock7m, bytecount, enable, byte, ready);
	/* connected to external buffer interface */
	input [7:0] datain;
	output read_buffer;
	input read_done_req;

	/* to clock generator */
	input clock10;
	input clock7m;

	/* to low level shifter */
	output [7:0] byte;
	output ready;

	input [11:0] bytecount;	/* how many bytes in the send buffer? */
	input enable;

	wire [7:0] datain;
	reg read_buffer;
	
	wire [11:0] bytecount;

	reg [7:0] byte;

	reg ready;
	
	reg read_done_ack;
	wire read_done= read_done_req ^ read_done_ack;
	
/*	initial begin
		ready= 1'b0;
		read_buffer= 1'b0;
		read_done_ack= 1'b0;
	end
*/
// acknowledge byte from buffer, signal shiftout to send it out the port
	always @(posedge clock7m)
		if ( ~enable ) ready=1'b0;
		else if (clock10 & read_done) begin
			read_done_ack= ~read_done_ack;
			ready= ~ready;
			byte=datain;
		end
	
// One every byte type, request byte from send buffer if any.
	always @(posedge clock7m)
		if ( ~enable ) read_buffer= 1'b0;
		else if (clock10 & bytecount != 12'b0) read_buffer= ~read_buffer;
			
endmodule

/* interface to 8k external SRAM */
`define CPU_READ 3'd0
`define SERIAL_READ 3'd1
`define SERIAL_WRITE 3'd2
`define CPU_WRITE 3'd3
`define IDLE 3'd4

module buffer(	cpu_dataout, serial_dataout, CPUin, serial_in, 
		cpu_read_req, cpu_write_req, serial_read_req, serial_write_req,
		serial_read_done,
		sram_data, sram_write_latch, sram_addr, sram_output_enable, sram_write_enable,
		send_bytecount, recv_bytecount,
		clock7m, CDAC, enable );

	output [7:0] cpu_dataout;
	output [7:0] serial_dataout;
	input [7:0] CPUin;
	input [7:0] serial_in;
	input cpu_read_req, cpu_write_req, serial_read_req, serial_write_req;
	output serial_read_done;

	/* signals for controling external sram */
	input [7:0] sram_data;
	output [7:0] sram_write_latch;
	output [12:0] sram_addr;
	output sram_output_enable, sram_write_enable;

	output [11:0] send_bytecount, recv_bytecount;

	input clock7m, CDAC;	/* 7Mhz system clocks, 45 degress out of phase */
	input enable;

	reg [12:0] sram_addr;
	reg sram_output_enable;
	wire sram_write_enable;
	wire [7:0] sram_data;

	reg [7:0] sram_write_latch;	/* sram write data latch */

	reg [7:0] cpu_dataout;
	reg [7:0] serial_dataout;
	wire [7:0] CPUin;
	wire [7:0] serial_in;
	reg [11:0] cpu_write_addr;
	reg [11:0] cpu_read_addr;
	reg [11:0] serial_in_addr;
	reg [11:0] serial_out_addr;
	wire cpu_read_req, cpu_write_req, serial_read_req, serial_write_req;
	reg serial_read_done;


	reg cpu_read_ack, cpu_write_ack, serial_read_ack, serial_write_ack;
	wire cpu_read = cpu_read_req ^ cpu_read_ack;
	wire cpu_write= cpu_write_req ^ cpu_write_ack;
	wire serial_read = serial_read_req ^ serial_read_ack;
	wire serial_write = serial_write_req ^ serial_write_ack;
	
	reg [11:0] send_bytecount, recv_bytecount;

	reg [2:0] state;

/*	initial begin
		state= 4'd8;
		sram_output_enable=1'b1;
		sram_chip_select=1'b1;
		send_bytecount=12'd0;
		recv_bytecount=12'd0;
		serial_read_done= 1'b0;
		cpu_read_ack= 1'b0;
		cpu_write_ack= 1'b0;
		serial_read_ack= 1'b0;
		serial_write_ack= 1'b0;
		serial_read_done= 1'b0;
	end
*/

	initial begin
		cpu_write_addr=12'b0;
		cpu_read_addr=12'b0;
		serial_in_addr=12'b0;
		serial_out_addr=12'b0;
	end

	assign sram_write_enable= ~(sram_output_enable & ~clock7m & ~CDAC );

	always @(posedge CDAC)
		if ( ~enable ) begin
			state=`IDLE;
			sram_output_enable=1'b0;
		end 
		else casex ({cpu_read, cpu_write, serial_read, serial_write}) 
			4'b1???: begin
				sram_addr={1'b0,cpu_read_addr};
				sram_output_enable=1'b0;
				state=`CPU_READ;
			      end
			4'b01??: begin
				sram_output_enable=1'b1;
				sram_addr={1'b1,cpu_write_addr};
				sram_write_latch=CPUin;
				state=`CPU_WRITE;
			      end
			4'b0010: begin
				sram_addr={1'b1,serial_out_addr};
				sram_output_enable=1'b0;
				state=`SERIAL_READ;
			      end
			4'b00?1: begin
				sram_output_enable=1'b1;
				sram_addr={1'b0,serial_in_addr};
				sram_write_latch=serial_in;
				state=`SERIAL_WRITE;
			      end
			default: begin
				sram_output_enable=1'b0;
				state=`IDLE;
			end
		endcase

//	always @(negedge clock7m)
	always @(negedge CDAC)
		if (~enable) begin
			cpu_read_ack= 1'b0;
			recv_bytecount=12'b0;
			serial_read_ack= 1'b0;
			send_bytecount= 12'b0;
			serial_write_ack= 1'b0;
			cpu_write_ack= 1'b0;
			serial_read_done= 1'b0;
			cpu_read_addr= serial_in_addr;
			serial_out_addr= cpu_write_addr;
		end else casex (state) 
			`CPU_READ: begin
					cpu_read_ack= ~cpu_read_ack;
					cpu_read_addr= sram_addr[11:0] + 1;	/* cpu_read_addr++ (saves a latch) */
					cpu_dataout=sram_data;
					recv_bytecount= recv_bytecount - 1;
				   end
			`SERIAL_READ: begin
					serial_read_ack= ~serial_read_ack;
					serial_out_addr= sram_addr[11:0]+1;
					serial_dataout=sram_data;
					send_bytecount= send_bytecount - 1;
					serial_read_done= ~serial_read_done;
				   end
			`SERIAL_WRITE: begin
					serial_write_ack= ~serial_write_ack;
					serial_in_addr= sram_addr[11:0]+1;
					recv_bytecount= recv_bytecount + 1;
				   end
			`CPU_WRITE: begin
					cpu_write_ack= ~cpu_write_ack;
					cpu_write_addr= sram_addr[11:0]+1;
					send_bytecount= send_bytecount + 1;
				   end
		endcase

//	ALways @(negedge CDAC)
//		If ( ~enable ) serial_read_done= 1'b0;
//		Else if (state == `SERIAL_READ) serial_read_done= ~serial_read_done;

endmodule


/* define external signals to CPLD */
`define FLAG 8'h7E

module recvdata(dataout, write_buffer, clock7m, charmode, interupt, interupt_ack,
		bytecount, remove_byte, cd, watchdog, byte, ready_req, enable); 
	/* signals for buffering system */
	output [7:0] dataout;
	output write_buffer;

	input clock7m;	/* 7Mhz system clock */
	output charmode;	/* mode select.  active for character by character mode, inactive for packet */

	output interupt;	/* goes to edge card interupt line */
	input interupt_ack;	/* active when data is read by cpu */

	input [11:0] bytecount;	/* tell cpu interface how many bytes are in the receive buffer */
	input remove_byte;		/* signal that the cpu has read a byte */
	input cd;			/* RS232 Carrier detect signal */
	input watchdog;			/* very slow ( ~120Hz ) clock used to signal CPU intervention
					   when packet boundary detection fails */ 
	/* signals for low level data receiver */
	input [7:0] byte;	/* byte received from port */
	input ready_req;		/* signal from uart that we have a byte */

	input enable;		

	reg [7:0] dataout;
	reg write_buffer;
	reg charmode;
	reg interupt;
	
	wire [7:0] byte;
	wire ready_req;

	reg ready_req_reg, ready_ack;
	wire ready= ready_req_reg ^ ready_ack;

	reg [2:0] sequence;	/* sequence position in check for PPP signature */
	reg unchecked;		/* flag to indicate that bytes have been received since the last cpu read */
	
	/* initialize */
/*	initial begin
		write_buffer=1'b0;
		ready_ack=1'b0;
	end
*/

	/* confine cross clock metastability headaches to ready flag */
	always @(negedge clock7m)
		ready_req_reg=ready_req;
		
	always @(posedge clock7m)
		if ( ~enable ) begin
			write_buffer=1'b0;
			ready_ack= 1'b0;
		end
		else if (ready) begin
			dataout=byte;
			ready_ack= ~ready_ack;
			write_buffer= ~write_buffer;
		end

	always @(posedge clock7m)
		if ( remove_byte || interupt || ~enable ) unchecked=1'b0;
		else if ( ready || 	// watch on character in
		 	( watchdog & (bytecount != 12'd0) ) ) unchecked=1'b1;  // watch for straglers

	always @(posedge clock7m)
		if (interupt_ack || ~enable ) interupt=1'b0;	// acknowledge cpu read  
		else if ( ( ready & (dataout == `FLAG || charmode) ) ||  // normal interupt
		 	( unchecked & watchdog ) ) interupt=1'b1;  // watchdog

	always @(posedge clock7m)
		if (~cd || ~enable ) begin
			charmode=1; 	/* always start in character mode */
			sequence= 3'd0;
		end
		else if ( ready ) begin
			if ( byte == 8'h7E ) sequence= 3'd1;
			else case (sequence)
			3'd1:	case (byte)
					8'hFF: sequence = 3'd2;
					8'h7D: sequence = 3'd6;	/* alternate sequence */
					default: sequence = 3'd0;
				endcase
			3'd2:	if (byte == 8'h7D) sequence = 3'd3;
				else sequence = 3'd0;
			3'd3:	if (byte == 8'h23) sequence = 3'd4;
				else sequence = 3'd0;
			3'd4:	if (byte == 8'hC0) sequence = 3'd5;
				else sequence = 3'd0;
			3'd5:	if (byte == 8'h21) charmode=0;	/* PPP detected! */
				else sequence = 3'd0;
			3'd6:	if (byte ==  8'hDF) sequence = 3'd2;	/* rejoin the main sequence */
				else sequence = 3'd0;
			endcase
              end
endmodule

module shiftin(byteout, ready, clock16x, clockref, rd, enable);
	output [7:0] byteout;
	output ready;

	input clock16x;		/* 16x recieve clock from clockgen */
	input clockref;		/* 7.3Mhz reference clock for buad rate generation */
	input rd;		/* rs232 receive data line from tranceiver */

	input enable;

	reg [6:0] byte;
	reg [7:0] byteout;
	reg ready;
	reg [3:0] bitcount;

	reg [3:0] sample_num;

	wire rd;	/* receive data line */

	reg [0:3] bit4;
	reg hunt_startbit_req, hunt_startbit_ack;
	reg bitclock;

	reg clock16x_delay;	// clock16x delayed by 45 degrees from clockref

	always @(negedge clockref) clock16x_delay = clock16x;
		
//	initial sample_num_next=4'b0;

	wire hunt_startbit = hunt_startbit_req ^ hunt_startbit_ack;

	always @(negedge clockref)
		if (~enable) begin
			hunt_startbit_req= 1'b1;
			ready=1'b0;
		end
		else if (bitclock & clock16x)
		casex (bitcount)
			0: begin 
				byte[0] = rd;
				bitcount = 4'd1;
			   end
			1: begin 
				byte[1] = rd;
				bitcount= 4'd2;
			   end
			2: begin 
				byte[2] = rd;
				bitcount= 4'd3;
			   end
			3: begin 
				byte[3] = rd;
				bitcount= 4'd4;
			   end
			4: begin 
				byte[4] = rd;
				bitcount= 4'd5;
			   end
			5: begin 
				byte[5] = rd;
				bitcount= 4'd6;
			   end
			6: begin 
				byte[6] = rd;
				bitcount= 4'd7;
			   end
			7: begin 
				byteout={rd, byte[6:0]};
				bitcount= 4'd8;
				ready= ~ready;
				hunt_startbit_req= ~hunt_startbit_req;
			   end
			default: bitcount= 4'd0;  // start bit
		endcase 

/*	initial begin
		sample_num=4'b0;
		bitclock=1'b0;
		bitcount=4'd8;
		ready=1'b0;
		hunt_startbit_req= 1'b1;
		hunt_startbit_ack= 1'b0;
	end
*/		
	always @(sample_num) 	#1 if (sample_num == 4'd15) bitclock=1'b1; 
				else bitclock=1'b0;

	always @(posedge clockref)
		if (~hunt_startbit & clock16x_delay) sample_num= sample_num + 1;
		else if (hunt_startbit) sample_num= 4'd10;

	always @(posedge clockref)
		if (~enable) hunt_startbit_ack= 1'b0;
		else if ( hunt_startbit & bit4 == 4'b1100 ) 
			hunt_startbit_ack= ~hunt_startbit_ack;
		
//	always @(negedge clock16x) bit4= {bit4next[1:3], rd};
	always @(negedge clockref)
		if (~enable) bit4= 4'b1111;
		else if (clock16x) bit4= {bit4[1:3], rd};

endmodule


module cpu_access(	bus_data_in, bus_data_out, clock7m,
			write_bus, card_select, data_strobe, bus_read_write, f_select,
			serial_data_in, serial_data_out, 
			read, write,
			send_byte_count, receive_byte_count,
			cts, cd, dsr, rts, dtr, 
			divisor, hard_enable, soft_enable, charmode );

	/* signals connected to zorro bus */
	input [9:0] bus_data_in;
	output [15:0] bus_data_out;
	input clock7m;

	/* signals controling the chips's bus interface */
	output write_bus;
	input card_select;
	input data_strobe;	/* active low.  Active if address and data buses are settled */ 
	input bus_read_write;
	input [3:0] f_select;

	/* signals connected to buffer system */
	input [7:0] serial_data_in;
	output [7:0] serial_data_out;
	output read, write;

	input [11:0] send_byte_count;
	input [11:0] receive_byte_count;

	/* serial control signals */
	input cts, cd, dsr;
	output rts, dtr;

	/* uart controls */
	output [7:0] divisor; 
	input hard_enable;
	output soft_enable;		/* 1 = active.  0 = inactive */
	input charmode;
	
	wire [9:0] bus_data_in;
	reg [15:0] bus_data_out, uart_state_latch;
	wire bus_read_write;

	reg write_bus;

//	wire [7:0] serial_data_in;
	wire [7:0] serial_data_out;
	reg read, write;	/* read/write buffer */

	reg rts, dtr;

	reg [7:0] divisor;
	reg soft_enable;
	reg started;

/*	initial begin
		divisor=8'b0;
		soft_enable=1'b0;
		started=1'b0;
	end
*/
//	always @(negedge card_select) write_bus=1'b0;

	always @(posedge clock7m) 
		if (~card_select) started=1'b0;
		else if (~data_strobe) started= 1'b1;
	
	/* master control function selector */
	always @(posedge clock7m) 
		if ( ~hard_enable ) begin
			write=1'b0;
			dtr= 1'b0;
			rts= 1'b0;
		end
		else if (card_select & ~data_strobe & ~bus_read_write)
		case ( f_select[2:0] )	/* function select */
			3'h0:	begin	/* send byte */
					if (~started) write= ~write;
				end
			3'h1:	begin	/* write status */
//					rts= bus_data_in[12];
//					dtr= bus_data_in[11];
					rts= bus_data_in[9];
					dtr= bus_data_in[8];
					divisor= bus_data_in[7:0];
				end
			3'h2:	begin	/* write divisor */
					divisor= bus_data_in[7:0];
				end
			3'h3:	begin	/* write rts */
					rts= bus_data_in[0];
				end
			3'h4:	begin	/* write dtr */
					dtr= bus_data_in[0];
				end
			3'h5:	begin	/* write enable */
					soft_enable= bus_data_in[0];
				end
		endcase

	always @(posedge clock7m)  /* receive byte */
		if (~hard_enable | ~soft_enable) read= 1'b0;
		else if ( bus_read_write & card_select & 
			f_select[2:0] == 3'b0 & ~started) read= ~read;

	always @(posedge clock7m) 
		if ( ~card_select | ~hard_enable) write_bus= 1'b0;
		else if (~data_strobe & bus_read_write) write_bus= 1'b1;

	/* For now, route bytes from the bus directly to the sram buffer.
	   I may someday put a latch here, but right now I don't see the need */
	assign serial_data_out= bus_data_in[7:0];

	always @(f_select or soft_enable or cd or cts or dsr or send_byte_count 
		or receive_byte_count or divisor or rts or dtr or charmode)
		case (f_select)
				/* read status */
			4'h1: uart_state_latch= {cd, cts, dsr, rts, dtr, charmode, soft_enable, 1'b0, divisor}; 
				/* read divisor */
			4'h2: uart_state_latch= {8'h00, divisor}; 
				/* read rts */
			4'h3: uart_state_latch= {15'b0, rts};
				/* read dtr */
			4'h4: uart_state_latch= {15'b0, dtr};
				/* read enable */
			4'h5: uart_state_latch= {15'b0, soft_enable};
				/* read cd */
			4'h6: uart_state_latch= {15'b0, cd};
				/* read cts */
			4'h7: uart_state_latch= {15'b0, cts};
				/* read dsr */
			4'h8: uart_state_latch= {15'b0, dsr};
				/* read # of bytes in send buffer */
			4'h9: uart_state_latch= {4'b0,send_byte_count};
				/* read # of bytes in receive buffer */
			default: uart_state_latch= {4'b0,receive_byte_count};
		endcase

	always @(bus_data_out or f_select or uart_state_latch or bus_read_write or serial_data_in)
		if ({bus_read_write, f_select} == 5'h10) 
			bus_data_out= {uart_state_latch[15:8], serial_data_in};
		else bus_data_out= uart_state_latch;

endmodule

/* this module controls autoconfig and generates various selects */
module config(	BUSRST, CFGIN, CFGOUT, READ, AS, low_data_strobe, address, 
		data_bus8, card_select, enable, hard_enable, soft_enable, 
		rom_select, rom_out, clock7m);
	input BUSRST, CFGIN;
	output CFGOUT;
	input READ, AS, low_data_strobe;
	input [23:1] address;	/* Zorro II address bus */
	input [7:0] data_bus8;	/* lower 8 bits of data bus */
	output card_select; 
	output enable;
	output hard_enable;
	input soft_enable;
	output rom_select;
	output [3:0] rom_out;
	input clock7m;

	reg CFGOUT;	/* configure the next card */
//	wire CFGOUT=1;	// see if something hokey is going on 
	wire card_select; 	/* notify other modules that it is ok to respond */
	wire enable; 		/* active high if everthing is enabled */
	reg hard_enable; 	/* disable low if told to reset by external signal */
	wire soft_enable; 	/* disable low requested by software */
	wire rom_select;
	reg [3:0] rom_out;
	reg [7:0] card_address;

	wire config_access, config_select;

	/* load card address */
	assign config_access = ~CFGIN & CFGOUT & ~AS; 
	assign config_select = (address[23:8] == 16'hE800 );
//	assign config_select = (address[23:16] == 8'hE8 );

/*	initial begin
		CFGOUT=1'b1;
		hard_enable=1'b0;
	end
*/
	always @(posedge clock7m)
		if (~BUSRST | CFGIN ) CFGOUT=1'b1;
		else if ( config_access & config_select & ~READ
			&  ({address[6:1],1'b0} == 7'h48) & ~low_data_strobe ) begin
				card_address = data_bus8;
				CFGOUT=1'b0;
			end

	
	/* enable configuration ROM */
	assign rom_select = config_access & config_select & READ;

	/* enable normal interface */
	assign card_select = ~AS & ~CFGOUT & (address[23:16] == card_address);
                                        
	always @(BUSRST or CFGIN) 
		if (~BUSRST || CFGIN) hard_enable=1'b0;
		else hard_enable=1'b1;

	assign enable= hard_enable & soft_enable;

	always @(address[6:1] )
		case ( {address[6:1], 1'b0} )
			7'h00: rom_out= { 2'b11, 1'b0, 1'b0 };
			7'h02: rom_out= ~{ 1'b0, 3'b001 };
			7'h04: rom_out= ~(4'h6);
			7'h08: rom_out= ~{ 1'b0, 1'b1, 1'b0, 1'b1 };
			7'h10: rom_out= ~4'h4;
			7'h14: rom_out= ~4'h2;
			default: rom_out= 4'b1111;
		endcase

endmodule
