📄 lpc_fsm.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 + -