⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpc_fsm.v

📁 LPC总线从设备的verilog设计,包含状态机和中断功能。
💻 V
字号:
//                              -*- Mode: Verilog -*-
// Filename        : lpc_fsm.v
// Description     : LPC FSM for I/O Operation
// Author          : James Rao
// Created On      : Wed Dec 17 10:37:41 2008
// Last Modified By: .
// Last Modified On: .
//--------------------------------------------------------------------------------
// Copyright (c) by Kontron (China) Ltd. This model is the confidential and
// proprietary property of Kontron Ltd. And the possession or use of this
// file requires a written license from Kontron (China) Ltd.
//--------------------------------------------------------------------------------
// Update Count    : 0
// Status          : Unknown, Use with caution!
//
// Updata History  :
// Version     Date        Author      Description
//   0.1     2008-12-17  James Rao   Initial design

`include "../define.v"

module lpc_fsm (/*AUTOARG*/
   // Outputs
   lad_out_en, lad_out, csr_ren, csr_wen, csr_din, csr_offset, 
   bios_post_wr, led_test_wr, 
   // Inputs
   reset_n, clk, lframe_n, lad_in, csr_dout
   ) ;

   // Global interface.
   input 			  reset_n;
   input 			  clk;

   // LPC interface
   input 			  lframe_n;
   input [3:0] 			  lad_in;
   
   output 			  lad_out_en;
   output [3:0] 		  lad_out;

   output 			  csr_ren;
   output 			  csr_wen;
   output [7:0] 		  csr_din;
   output [3:0] 		  csr_offset;

   output 			  bios_post_wr;
   output 			  led_test_wr;
   
   //MISC
   input [7:0] 			  csr_dout;

   //FSM Parameter declaration
   parameter 			  IDLE       = 3'h0,
				  CYC_TYPE   = 3'h1,
				  ADDR_PHASE = 3'h2,
				  DATA_IOW   = 3'h3,
				  TA_HOST    = 3'h4,
				  SYNC_SLV   = 3'h5,
				  DATA_IOR   = 3'h6,
				  TA_SLV     = 3'h7;
   
   reg [2:0] 			  ns;
   reg [2:0] 			  cs;

   reg [1:0] 			  cyc_cntr;
   reg 				  io_wr;
   reg [15:0] 			  io_addr;
   
   reg [7:0] 			  csr_din;
   reg 				  lad_out_en;
   reg [3:0] 			  lad_out;
   reg 				  csr_ren;
   reg 				  csr_wen;
   reg				  bios_post_wr;
   reg 				  led_test_wr;

   wire 			  addr_hit;

   /***************************************************************************
                             1. Control FSM for LPC I/F
                      Support I/O read/write operation only!!!
    ***************************************************************************/
   always @(posedge clk or negedge reset_n) begin
      if (!reset_n)
	cs <= #1 IDLE;
      else
	cs <= #1 ns;
   end

   always @(/*AUTOSENSE*/addr_hit or cs or cyc_cntr or io_wr or lad_in
	    or lframe_n) begin
      case (cs)
	IDLE: begin
	   if (!lframe_n && (lad_in == 4'h0))//START frame for MEM/IO/DMA supported.
	     ns = CYC_TYPE;
	   else
	     ns = IDLE;
	end

	CYC_TYPE: begin
	   if (!lframe_n) begin //long START phase
	      if (lad_in == 4'h0)//still START frame supported
		ns = CYC_TYPE;
	      else//other START cycle not supported.
		ns = IDLE;
	   end
	   else begin//Cycle Type phase
	      if (lad_in[3:2] == 2'b00) //I/O read/write operation
		ns = ADDR_PHASE;
	      else//other operations not supported
		ns = IDLE;
	   end // else: !if(lframe_n == 1'b0)
	end // case: CYC_TYPE
	
	ADDR_PHASE: begin
	   if (!lframe_n) //host abort
	     ns = IDLE;
	   else if (cyc_cntr == 2'b11) begin//16-bit address
	      if (io_wr)//I/O write operation, jump to DATA phase
		ns = DATA_IOW;
	      else//I/O write operation, jump to Turn-around phase.
		ns = TA_HOST;
	   end
	   else
	     ns = ADDR_PHASE;
	end // case: ADDR_PHASE
	
	DATA_IOW: begin
	   if (!lframe_n) //host abort
	     ns = IDLE;
	   else if (cyc_cntr == 2'b01)
	     ns = TA_HOST;
	   else
	     ns = DATA_IOW;	   
	end
	
	TA_HOST: begin
	   if (!lframe_n) //host abort
	     ns = IDLE;
	   else begin
	      if (!addr_hit)//not targetting this device
		ns = IDLE;
	      else if (cyc_cntr == 2'b01)
		ns = SYNC_SLV;
	      else
		ns = TA_HOST;
	   end
	end // case: TA_HOST

	SYNC_SLV: begin
	   if (!lframe_n) //host abort
	     ns = IDLE;
	   else if (io_wr)//I/O write operation
	     ns = TA_SLV;
	   else//I/O read operation
	     ns = DATA_IOR;
	end

	DATA_IOR: begin
	   if (!lframe_n) //host abort
	     ns = IDLE;
	   else if (cyc_cntr == 2'b01)
	     ns = TA_SLV;
	   else
	     ns = DATA_IOR;
	end

	TA_SLV: begin
	   ns = IDLE;
	end
	
	default: begin
	   ns = IDLE;
	end
      endcase // case(cs)
   end // always @ (...
	   
   /***************************************************************************
                           2. FSM Control & Output Signals
    ***************************************************************************/
   //1) 2-bit cycle counter.
   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n)
	cyc_cntr <= #1 2'b00;
      else begin
	 case (cs)	   
	   ADDR_PHASE: begin
	      cyc_cntr <= #1 cyc_cntr + 1;
	   end
	   
	   TA_HOST, DATA_IOR, DATA_IOW: begin
	      if (cyc_cntr == 2'b01)
		cyc_cntr <= #1 2'b0;
	      else
		cyc_cntr <= #1 cyc_cntr + 1;
	   end
	   default: cyc_cntr <= #1 2'b00;
	 endcase // case(cs)
      end
   end
   
   //2) I/O Read/Write flag -- 1'b1: write;    1'b0: read;
   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n)
	io_wr <= #1 1'b0;
      else if (lframe_n && (lad_in[3:1] == 3'b001) && (cs == CYC_TYPE))
	io_wr <= #1 1'b1;
      else if (cs == IDLE)
	io_wr <= #1 1'b0;
   end

   //3) I/O address for the operation.
   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n)
	io_addr <= #1 16'h0;
      else if (cs == ADDR_PHASE) begin
	 case (cyc_cntr)//MSB first for ADDRESS
	   2'b00: io_addr[15:12] <= #1 lad_in;
	   2'b01: io_addr[11:8]  <= #1 lad_in;
	   2'b10: io_addr[7:4]   <= #1 lad_in;
	   2'b11: io_addr[3:0]   <= #1 lad_in;
	 endcase // case(cyc_cntr)
      end      
   end // always@ (posedge clk or negedge reset_n)

   //4) Base address hit flag, last till the end of the cycle.
   assign addr_hit = io_addr[`BAR_BITS] == `BASE_ADDR;

   //5) Data input for I/O write operation, and corresponding write read signal.
   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n) begin
	 csr_wen <= #1 1'b0;
	 csr_din <= #1 8'h0;
      end
      else if (cs == DATA_IOW) begin
	 if (cyc_cntr[0]) begin
	    csr_wen <= #1 addr_hit & io_wr;
	    csr_din[7:4] <= #1 lad_in;
	 end
	 else begin
	    csr_wen <= #1 1'b0;
	    csr_din[3:0] <= #1 lad_in;//LSB forst for DATA
	 end
      end
      else
	csr_wen <= #1 1'b0;
   end // always@ (posedge clk or negedge reset_n)

   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n)
	csr_ren <= #1 1'b0;
      else if ((cs == TA_HOST) && ~cyc_cntr[0])
	csr_ren <= #1 addr_hit & ~io_wr;
      else
	csr_ren <= #1 1'b0;
   end

   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n) begin
	 bios_post_wr <= #1 1'b0;
	 led_test_wr <= #1 1'b0;
      end
      else begin
	 bios_post_wr <= #1 (cs == DATA_IOW) & cyc_cntr[0] & (io_addr == `BIOS_POST_PORT);
	 led_test_wr <= #1 (cs == DATA_IOW) & cyc_cntr[0] & addr_hit & (io_addr[`OFFSET_BITS] == `OFFSET_LED_DAT);
      end
   end

   assign csr_offset = io_addr[`OFFSET_BITS];

   //6) data to be driven on lad[3:0] and lad driven enable.
   /*SYNC encoding
    4'h0: Read -- SYNC without error;
    4'h1~4'h4: Reserved;
    4'h5: Short Wait -- Max. 8-cycles;
    4'h6: Long Wait -- No limitation;
    4'h7~4'h8: Reserved;
    4'h9: Ready more. for DMA only;
    4'hA: error, to replace SERR#/IOCHK# signal;
    4'hB~4'hF: Reserved.
   */
   always@ (posedge clk or negedge reset_n) begin
      if (!reset_n) begin
	 lad_out_en <= #1 1'b0;
	 lad_out <= #1 4'h0;
      end
      else begin
	 case (cs)
	   TA_HOST: begin
	      lad_out_en <= #1 addr_hit & cyc_cntr[0];
	      lad_out <= #1 4'h0;// ready -- SYNC without error.
	   end
	   SYNC_SLV: begin
	      if (~io_wr) begin
		 lad_out_en <= #1 addr_hit;
		 lad_out <= #1 csr_dout[3:0];//I/O read data -- first nibble
	      end
	      else begin
		 lad_out_en <= #1 addr_hit;
		 lad_out <= #1 4'hF;//Slave turn around -- first cycle.
	      end
	   end
	   DATA_IOR: begin
	      lad_out_en <= #1 addr_hit & ~io_wr;
	      if (cyc_cntr[0] == 1'b0)
		lad_out <= #1 csr_dout[7:4];
	      else//Turn around -- first cycle.
		lad_out <= #1 4'hF;// drive LAD high for 1-cycle and then tri-state.
	   end
	   default: begin
	      lad_out_en <= #1 1'b0;
	      lad_out <= #1 4'h0;
	   end
	 endcase // case(cs)	 
      end // else: !if(!reset_n)
   end // always@ (posedge clk or negedge reset_n)
   
      
endmodule // lpc_fsm

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -