pi_ioc.v 6.78 KB
// pi_ioc.v v1 Frank Berndt
// pi io bus controller;
// :set tabstop=4

module pi_ioc (
	sysclk, reset,
	io_in, io_ena, io_out, io_oe, io_ale,
	io_ior, io_iow, io_cs, io_dmarq, io_dmack, io_intr,
	flc_breq, flc_bgnt, flc_bre, flc_brd, flc_out,
	but_req, but_val,
	ide_conf, ide_stall,
	ide_acc, ide_req, ide_addr, ide_write, ide_rack, ide_do, ide_di,
	ide_intr
);
	// module io ports;

	input sysclk;			// system clock;
	input reset;			// controller and system reset;

	// generic ide bus interface;

	input [15:0] io_in;		// io bus input data;
	output io_ena;			// io input register clock enable;
	output [15:0] io_out;	// io bus output data;
	output [1:0] io_oe;		// io bus output enables;
	output io_ale;			// io address latch enable;
	output io_ior;			// io read pulse;
	output io_iow;			// io write pulse;
	output [3:0] io_cs;		// io pio chip selects;
	input io_dmarq;			// io dma request;
	output io_dmack;		// io dma acknowledge;
	input io_intr;			// io device interrupt;

	// flash controller interface;

	input flc_breq;			// flash bus request;
	output flc_bgnt;		// flash bus grant;
	input flc_bre;			// flash bus read enable;
	input flc_brd;			// flash bus read;
	input [15:0] flc_out;	// flash output data;

	// si button interface;

	input but_req;			// request button sample;
	output but_val;			// button sample valid;

	// io controller interface;

	input [30:0] ide_conf;	// ide timing config;
	output ide_stall;		// ide pio in progress;
	input ide_acc;			// ide access granted;
	input ide_req;			// ide pio request;
	input [18:1] ide_addr;	// ide bus address;
	input ide_write;		// ide pio write;
	output ide_rack;		// ide read acknowledge;
	input [31:0] ide_do;	// ide pio write data;
	output [15:0] ide_di;	// ide pio read data;
	output ide_intr;		// ide interrupt;

	// ide bus arbiter interface;

	reg ide_breq;			// ide bus request;
	wire ide_bgnt;			// ide bus grant;
	reg ide_bre;			// ide bus read enable;
	reg ide_brd;			// ide bus read;
	wire [15:0] ide_out;	// ide output data;

	// io bus arbiter;
	// fixed priority arbitration;
	// requestor keeps request active for duration of bus cycle;
	// requestor is responsible for bus cycle timing;
	// 000=idle, 001=flash, 010=button port, 100=ide;

	reg but_breq;			// pending button request;
	reg [2:0] io_arb;		// arbitration winner;
	wire io_arb_dis;		// disable io arbiter;
	wire io_arb_en;			// enable io arbiter;

	always @(posedge sysclk)
	begin
		if(reset)
			io_arb <= 3'd0;
		else if(io_arb_en) begin
			io_arb[0] <= flc_breq;
			io_arb[1] <= ~flc_breq & but_breq;
			io_arb[2] <= ~flc_breq & ~but_breq & ide_breq;
		end
	end

	assign io_arb_dis = |(io_arb & { ide_breq, but_breq, flc_breq });
	assign io_arb_en = ~io_arb_dis;

	assign flc_bgnt = io_arb[0];
	assign ide_bgnt = io_arb[2];

	// button sampling;
	// request from si is single pulse;
	// arbitrate io bus and return valid to si;
	// give io hardware two clocks to put data on io bus;

	reg [1:0] but_pipe;		// button cycle pipe;
	wire but_cs;			// chip select for butteon read;
	wire but_bre;			// button io read enable;

	always @(posedge sysclk)
	begin
		but_breq <= ~reset & ~but_pipe[1] & (but_breq | but_req);
		but_pipe <= { but_pipe[0], io_arb[1] };
	end

	assign but_cs = but_pipe[0] & but_breq;
	assign but_bre = but_pipe[1] & io_arb[1];
	assign but_val = but_pipe[0] & ~io_arb[1];

	// io bus output enable control;
	// drive out 0 when idle, turn around for reads;
	// this saves board pull resistors;
	// button sampler always reads;
	// disable outputs during pin reset to sample id;

	wire [1:0] io_rdis;		// byte lane read diables;

	assign io_rdis[1] = reset | io_arb[1] | ide_brd | (io_arb[0] & flc_brd);
	assign io_rdis[0] = reset | io_arb[1] | ide_brd;

	// io bus write data mux;
	// flash and ide are the only units that write;
	// direct output to registers in pad layer;

	assign io_out = ({16{io_arb[0]}} & flc_out) | ({16{io_arb[2]}} & ide_out);
	assign io_oe = ~io_rdis;
	assign io_ena = reset | (io_arb[0] & flc_bre) | but_bre | ide_bre;

	// ide bus controller;

	// request io bus for ide pio;
	// must keep request active for duration of cycle;
	// must latch io address and write flag;
	// ignore requests when cycle controller is still busy;

	wire ide_val;			// allowed ide request;
	wire ide_bclr;			// done with ide bus cycle;
	wire ide_tend;			// pio cycle end time;
	reg [18:1] ide_baddr;	// ide bus address;
	reg ide_bwr;			// ide bus write;
	reg [15:0] ide_wdata;	// ide write data;

	assign ide_val = ide_req & ide_acc & ~ide_breq;
	assign ide_bclr = reset | ide_tend;
	assign ide_stall = ide_breq;

	always @(posedge sysclk)
	begin
		ide_breq <= ~ide_bclr & (ide_breq | ide_val);
		if(ide_val) begin
			ide_baddr <= ide_addr;
			ide_bwr <= ide_write;
		end
		if(ide_val & ide_write)
			ide_wdata <= ide_addr[1]? ide_do[15:0] : ide_do[31:16];
	end

	// ide bus cycle control;
	// cycle is started after io bus arbiter granted bus to ide;
	// ide_sm increments, state is triggered from decodes;

	reg [5:0] ide_sm;		// state machine;
	wire ide_trwa;			// ior/iow assertion time;
	wire ide_trwd;			// ior/iow deassertion time;
	reg ide_iow;			// io write pulse;
	reg ide_ior;			// io read pulse;
	reg [1:0] ide_gp;		// ide grant pipe;

	always @(posedge sysclk)
	begin
		ide_sm <= {6{ide_bgnt}} & (ide_sm + 1);
		ide_iow <= ide_bgnt & ide_bwr & ~ide_trwd & (ide_iow | ide_trwa);
		ide_ior <= ide_bgnt & ~ide_bwr & ~ide_trwd & (ide_ior | ide_trwa);
		ide_gp <= { ide_bgnt & ide_gp[0], ide_bgnt };
	end

	assign ide_trwa = (ide_sm == { 1'b0, ide_conf[4:0] });
	assign ide_trwd = (ide_sm == { 1'b0, ide_conf[9:5] });
	assign ide_tend = (ide_sm == ide_conf[15:10]);

	assign io_ale = ide_bgnt & (ide_sm == 6'd0);
	assign io_iow = ide_iow;
	assign io_ior = ide_ior;
	assign io_cs[0] = (ide_bgnt & (ide_baddr[18:17] == 2'd0));
	assign io_cs[1] = (ide_bgnt & (ide_baddr[18:17] == 2'd1));
	assign io_cs[2] = (ide_bgnt & (ide_baddr[18:17] == 2'd2)) | but_cs;
	assign io_cs[3] = (ide_bgnt & (ide_baddr[18:17] == 2'd3));

	// ide write data mux;
	// select address or write data;

	assign ide_out = ide_gp[1]? ide_wdata : ide_baddr[16:1];

	// turn bus around for ide reads;
	// sample read data at ior deassertion time;
	// must store ide read data due to cbus read request latency;

	wire ide_rden;			// read data enable;

	assign ide_rden = ide_gp[1] & ~ide_bwr & ide_trwd;
	assign ide_di = io_in;

	always @(posedge sysclk)
	begin
		ide_brd <= ide_bgnt & ide_gp[0] & ~ide_bwr;
		ide_bre <= ide_rden;
	end

	// ack ide reads;
	// when access is disabled, then ack immediatedly;
	// when busy and read request, then ack immediatedly;
	// else, ack as soon as read data is available;

	reg ide_rack;			// ide read ack;

	always @(posedge sysclk)
	begin
		ide_rack <= (~ide_acc & ide_req & ~ide_write)
			| (ide_req & ide_breq & ~ide_write)
			| ide_rden;
	end

	// ide interrupt handling;

	assign ide_intr = io_intr;

	// XXX

	assign io_dmack = 0;

endmodule