OpenCores
URL https://opencores.org/ocsvn/wb_lpc/wb_lpc/trunk

Subversion Repositories wb_lpc

[/] [wb_lpc/] [trunk/] [rtl/] [verilog/] [wb_lpc_host.v] - Rev 3

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  $Id: wb_lpc_host.v,v 1.1 2008-03-02 20:46:40 hharte Exp $
////  wb_lpc_host.v - Wishbone Slave to LPC Host Bridge           ////
////                                                              ////
////  This file is part of the Wishbone LPC Bridge project        ////
////  http://www.opencores.org/projects/wb_lpc/                   ////
////                                                              ////
////  Author:                                                     ////
////      - Howard M. Harte (hharte@opencores.org)                ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2008 Howard M. Harte                           ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source 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 Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
 
`timescale 1 ns / 1 ns
 
`include "../../rtl/verilog/wb_lpc_defines.v"
 
//					I/O Write		I/O Read			DMA Read			DMA Write
//															
//	States - 1. H Start			H Start			H Start			H Start
//				2. H CYCTYPE+DIR	H CYCTYPE+DIR	H CYCTYPE+DIR	H CYCTYPE+DIR
//				3. H Addr (4)		H Addr (4)		H CHAN+TC		H CHAN+TC
//															H SIZE			H SIZE
//				4. H Data (2)		H TAR  (2)	 +-H DATA (2)		H TAR  (2)
//				5. H TAR  (2)		P SYNC (1+)	 |	H TAR  (2)	 +-P SYNC (1+)
//				6. P SYNC (1+)		P DATA (2)	 | H SYNC (1+)	 +-P DATA (2)
//				7. P TAR  (2)		P TAR  (2)	 +-P TAR  (2)		P TAR
//															
module wb_lpc_host(clk_i, nrst_i, wbs_adr_i, wbs_dat_o, wbs_dat_i, wbs_sel_i, wbs_tga_i, wbs_we_i,
						   wbs_stb_i, wbs_cyc_i, wbs_ack_o,
							dma_chan_i, dma_tc_i,
						   lframe_o, lad_i, lad_o, lad_oe
);
	// Wishbone Slave Interface
	input			clk_i;
	input 		nrst_i;				// Active low reset.
	input 		[31:0] wbs_adr_i;
	output   	[31:0] wbs_dat_o;
  	input 		[31:0] wbs_dat_i;
	input 		[3:0]	 wbs_sel_i;
	input			[1:0]	 wbs_tga_i;
  	input 		wbs_we_i;
	input 		wbs_stb_i;
	input 		wbs_cyc_i;
	output reg	wbs_ack_o;
 
	// LPC Master Interface
	output reg	lframe_o;			// LPC Frame output (active high)
	output reg	lad_oe;				// LPC AD Output Enable
	input	[3:0]	lad_i;				// LPC AD Input Bus
	output reg	[3:0] lad_o;		// LPC AD Output Bus
 
	// DMA-Specific sideband signals
	input	[2:0]	dma_chan_i;			// DMA Channel
	input			dma_tc_i;			// DMA Terminal Count
 
	reg	[12:0] state;				// Current state
	reg 	[2:0] adr_cnt;				// Address nibbe counter
	reg 	[3:0] dat_cnt;				// Data nibble counter
	reg 	[2:0] xfr_len;				// Number of nibbls for transfer
	wire	[2:0] byte_cnt = dat_cnt[3:1];	// Byte Counter
	wire			nibble_cnt = dat_cnt[0];	// Nibble counter
	reg 	[31:0] lpc_dat_i;			// Temporary storage for input word.
 
	//
	// generate wishbone register signals
	wire wbs_acc = wbs_cyc_i & wbs_stb_i;    // Wishbone access
	wire wbs_wr  = wbs_acc & wbs_we_i;       // Wishbone write access
 
	// Memory Cycle (tga== 1'b00) is bit 2=1 for LPC Cycle Type.
	wire	mem_xfr = (wbs_tga_i == `WB_TGA_MEM);
	wire	dma_xfr = (wbs_tga_i == `WB_TGA_DMA);
	wire	fw_xfr  = (wbs_tga_i == `WB_TGA_FW);
 
	assign wbs_dat_o[31:0] = lpc_dat_i;	
 
	always @(posedge clk_i or negedge nrst_i)
		if(~nrst_i)
		begin
			state <= `LPC_ST_IDLE;
			lframe_o <= 1'b0;
			wbs_ack_o <= 1'b0;
			lad_oe <= 1'b0;
			lad_o <= 4'b0;
			adr_cnt <= 3'b0;
			dat_cnt <= 4'h0;
			xfr_len <= 3'b000;
			lpc_dat_i <= 32'h00000000;
		end
		else begin
			case(state)
				`LPC_ST_IDLE:
					begin
						wbs_ack_o <= 1'b0;
						lframe_o <= 1'b0;
						dat_cnt <= 4'h0;						
 
						if(wbs_acc)		// Wishbone access starts LPC transaction
							state <= `LPC_ST_START;
						else
							state <= `LPC_ST_IDLE;
					end
				`LPC_ST_START:
					begin
						lframe_o <= 1'b1;
						if(~fw_xfr) begin		// For Memory and I/O Cycles
							lad_o 	<= `LPC_START;
							state 	<= `LPC_ST_CYCTYP;
						end
						else begin				// Firmware Read and Write Cycles
							if(wbs_wr)
								lad_o <= `LPC_FW_WRITE;
							else
								lad_o <= `LPC_FW_READ;
 
							state	<= `LPC_ST_ADDR;
						end
						lad_oe 	<= 1'b1;
						adr_cnt	<= ((mem_xfr | fw_xfr) ? 3'b000 : 3'b100);
					end
				`LPC_ST_CYCTYP:
					begin
						lframe_o	<= 1'b0;
						lad_oe 	<= 1'b1;				
 
						if(~dma_xfr)
							begin
								lad_o 	<= {1'b0,mem_xfr,wbs_wr,1'b0};		// Cycle Type/Direction for I/O or MEM
								state		<= `LPC_ST_ADDR;
							end
						else // it is DMA
							begin
								lad_o 	<= {1'b1,1'b0,~wbs_wr,1'b0};		// Cycle Type/Direction for DMA, r/w is inverted for DMA
								state		<= `LPC_ST_CHAN;
							end
					end
				`LPC_ST_ADDR:	// Output four nubbles of address.
					begin
						lframe_o <= 1'b0;		// In case we came here from a Firmware cycle, which skips CYCTYP.
 
						// The LPC Bus Address is sent across the bus a nibble at a time;
						// however, the most significant nibble is sent first.  For firmware and
						// memory cycles, the address is 32-bits.  Actually, for memeory accesses,
						// the most significant nibble is known as the IDSEL field.  For I/O,
						// the address is only 16-bits wide.
						case(adr_cnt)
							3'h0:
								lad_o <= wbs_adr_i[31:28];
							3'h1:
								lad_o <= wbs_adr_i[27:24];
							3'h2:
								lad_o <= wbs_adr_i[23:20];
							3'h3:
								lad_o <= wbs_adr_i[19:16];
							3'h4:
								lad_o <= wbs_adr_i[15:12];
							3'h5:
								lad_o <= wbs_adr_i[11:8];
							3'h6:
								lad_o <= wbs_adr_i[7:4];
							3'h7:
								lad_o <= wbs_adr_i[3:0];
						endcase
 
						adr_cnt <= adr_cnt + 1;
 
						if(adr_cnt == 4'h7) // Last address nibble.
							begin
								if(~fw_xfr)
									if(wbs_wr)
										state <= `LPC_ST_H_DATA;
									else
										state <= `LPC_ST_H_TAR1;
								else	// For firmware read/write, we need to transfer the MSIZE nibble
									state <= `LPC_ST_SIZE;
							end
						else
							state <= `LPC_ST_ADDR;
 
						lad_oe	<= 1'b1;
						xfr_len 	<= 3'b001;		// One Byte Transfer
					end
				`LPC_ST_CHAN:
					begin
						lad_o 	<= {dma_tc_i, dma_chan_i};
						state <= `LPC_ST_SIZE;
					end
				`LPC_ST_SIZE:
					begin
						case(wbs_sel_i)
							`WB_SEL_BYTE:
								begin
									xfr_len <= 3'b001;
									lad_o <= 4'h0;
								end
							`WB_SEL_SHORT:
								begin
									xfr_len <= 3'b010;
									lad_o <= 4'h1;
								end
							`WB_SEL_WORD:
								begin
									xfr_len <= 3'b100;
									if(fw_xfr)				// Firmware transfer uses '2' for 4-byte transfer.
										lad_o <= 4'h2;
									else						// DMA uses '3' for 4-byte transfer.
										lad_o <= 4'h3;
								end
							default:
								begin
									xfr_len <= 3'b001;
									lad_o <= 4'h0;
								end
						endcase
						if(wbs_wr)
							state <= `LPC_ST_H_DATA;
						else
							state <= `LPC_ST_H_TAR1;
					end
 
				`LPC_ST_H_DATA:
					begin
						lad_oe 	<= 1'b1;
						case(dat_cnt)	// We only support a single byte for I/O.
							4'h0:
								lad_o <= wbs_dat_i[3:0];
							4'h1:
								lad_o <= wbs_dat_i[7:4];
							4'h2:
								lad_o <= wbs_dat_i[11:8];
							4'h3:
								lad_o <= wbs_dat_i[15:12];
							4'h4:
								lad_o <= wbs_dat_i[19:16];
							4'h5:
								lad_o <= wbs_dat_i[23:20];
							4'h6:
								lad_o <= wbs_dat_i[27:24];
							4'h7:
								lad_o <= wbs_dat_i[31:28];
							default:
								lad_o <= 4'hx;
						endcase
 
						dat_cnt <= dat_cnt + 1;
 
						if(nibble_cnt == 1'b1) // end of byte
							begin
								state <= `LPC_ST_H_TAR1;
							end
						else
							state <= `LPC_ST_H_DATA;
					end
 
				`LPC_ST_H_TAR1:
					begin
						lad_o <= 4'b1111;		// Drive LAD high
						lad_oe <= 1'b1;
						state <= `LPC_ST_H_TAR2;
					end
				`LPC_ST_H_TAR2:
					begin
						lad_oe <= 1'b0;		// float LAD
						state <= `LPC_ST_SYNC;
					end
				`LPC_ST_SYNC:
					begin
						lad_oe <= 1'b0;		// float LAD
						if(lad_i == `LPC_SYNC_READY) begin
							if(wbs_wr) begin
								state <= `LPC_ST_P_TAR1;
							end
							else
								state <= `LPC_ST_P_DATA;
							end
						else
							state <= `LPC_ST_SYNC;
					end
 
				`LPC_ST_P_DATA:
					begin
						case(dat_cnt)
							4'h0:
								lpc_dat_i[3:0] <= lad_i;
							4'h1:
								lpc_dat_i[7:4] <= lad_i;
							4'h2:
								lpc_dat_i[11:8] <= lad_i;
							4'h3:
								lpc_dat_i[15:12] <= lad_i;
							4'h4:
								lpc_dat_i[19:16] <= lad_i;
							4'h5:
								lpc_dat_i[23:20] <= lad_i;
							4'h6:
								lpc_dat_i[27:24] <= lad_i;
							4'h7:
								lpc_dat_i[31:28] <= lad_i;
						endcase
 
						dat_cnt <= dat_cnt + 1;
 
						if(nibble_cnt == 1'b1)				// Byte transfer complete
							if (byte_cnt == xfr_len-1) 	// End of data transfer phase
								state <= `LPC_ST_P_TAR1;
							else
								state <= `LPC_ST_SYNC;
						else										// Go to next nibble
							state <= `LPC_ST_P_DATA;
					end
				`LPC_ST_P_TAR1:
					begin
						lad_oe <= 1'b0;
//						state <= `LPC_ST_P_TAR2;
//					end
//				`LPC_ST_P_TAR2:
//					begin
//						lad_oe <= 1'b0;		// float LAD
						if(byte_cnt == xfr_len) begin
							state <= `LPC_ST_IDLE;
							wbs_ack_o <= wbs_acc;
						end
						else begin
							if(wbs_wr) begin	// DMA READ (Host to Peripheral)
								state <= `LPC_ST_H_DATA;
							end
							else begin	// unhandled READ case
								state <= `LPC_ST_IDLE;
							end
						end
					end
			endcase
		end
 
endmodule
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.