📄 bkend_daemon.v
字号:
// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Copyright (c) 2001 by Lattice Semiconductor Corporation
// --------------------------------------------------------------------
//
// Permission:
//
// Lattice Semiconductor grants permission to use this code for use
// in synthesis for any Lattice programmable logic product. Other
// use of this code, including the selling or duplication of any
// portion is strictly prohibited.
//
// Disclaimer:
//
// This VHDL or Verilog source code is intended as a design reference
// which illustrates how these types of functions can be implemented.
// It is the user's responsibility to verify their design for
// consistency and functionality through the use of formal
// verification methods. Lattice Semiconductor provides no warranty
// regarding the use or functionality of this code.
//
// --------------------------------------------------------------------
//
// Lattice Semiconductor Corporation
// 5555 NE Moore Court
// Hillsboro, OR 97214
// U.S.A
//
// TEL: 1-800-Lattice (USA and Canada)
// 408-826-6000 (other locations)
//
// web: http://www.latticesemi.com/
// email: techsupport@latticesemi.com
//
// --------------------------------------------------------------------
// Revision History :
// --------------------------------------------------------------------
// Ver :| Author :| Mod. Date :| Changes Made:
// v1.0 D.S. 1/18/98 Initial Creation
// --------------------------------------------------------------------
//
// Module bkend_daemon
//
// This block is a daemon or behavioral model used to model the
// functionality of a generic bkend device. Any back end device
// if it's an SDRAM, SRAM, FIFO or simple I/O device will need
// control logic to arbitrate the backend signals from the PCI
// Target state machine.
// This daemon simply arbitrates the bkend signals, and reads and
// writes the data appropriatly. Depending on the address and bank written to,
// this daemon will respond normally, with a retry, a stop, an abort or an interupt.
//
// All reads and writes to bk0 will function normally. Bk1 has added
// functionality to test a retry, a stop, and an abort.
//
// If a write is made to address 20'h000A0 and bk1 the daemon will not
// respond with ready_l hence causing a data retry.
//
// If a write is made to address 20'h000B0 and bk1 the daemon will start
// the cycle then respond with data_stop_l == 0 causing a data stop.
//
// If a write is made to address 20'h000C0 and bk1 the daemon will start
// the cycle, but respond with bkend_abort_l == 0 causing a abort.
//
// If a write is made to address 20'h000D0 and bk1 the daemon will run
// the cycle, but respond with bkend_int_l == 0 causing a interruptto be
// passed through the PCI Target.
//
// If a write is made to address 20'h000E0 and bk1 the daemon will run
// the cycle, but respond with bkend_int_l == 1 causing the interruptto be
// disabled.
//
//
//
// NOTE: 1) To use the special features of bk1 the cycle must start with the
// specified address. In WILL burst by it with no effect.
//
///////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module bkend_daemon (bkend_ad, be_l, base_region0_l, base_region1_l, r_w_l,
bkend_dat, ready_l, data_write_l, data_read_l, data_stop_l, bkend_int_l,
bkend_abort_l, pci_clk, pci_rst_l);
input [19:0] bkend_ad;
input [3:0] be_l; // not used
input base_region0_l;
input base_region1_l;
input r_w_l;
input data_write_l; // used as a write strobe for the clock
input data_read_l; // used as a read strobe for the clock
input pci_clk;
input pci_rst_l;
inout [31:0] bkend_dat;
output ready_l;
output data_stop_l;
output bkend_int_l;
output bkend_abort_l;
// register declarations
reg [31:0] bkend_dat_reg;
reg [31:0] bk0 [63:0]; // 64 32 bit memory locations
reg [31:0] bk1 [63:0];
reg ready_l, data_stop_l, bkend_int_l, bkend_abort_l;
reg [3:0] state; // current state variable
reg [19:0] count; // the address counter
reg data_stop_flag, data_abort_flag;
// integer declarations
integer i;
// daemon state machine variables
parameter [3:0] idle = 4'h0,
first_data = 4'h1,
ready = 4'h2,
data_stop = 4'h3,
data_abort = 4'h4;
// The following block resets the memory banks
initial
begin
$display(" %m \t \t << Initializing Bkend memory banks 0 & 1 >>");
for ( i= 0; i < 64; i = i+1) begin
#1;
bk0[i] = 32'h0;
bk1[i] = 32'h0;
end // end of for loop
bkend_dat_reg = 32'b0;
data_stop_flag = 0;
data_abort_flag = 0;
end
// assigning the bkend_dat_reg to the output port bkend_dat
assign #4 bkend_dat = (r_w_l && (!base_region0_l || !base_region1_l)) ? bkend_dat_reg : 32'hZ;
// The following block of code controls the reads
// and writes to both bk0 and bk1. Note that on any
// given data cycle the state machine cycles from
// first_data to ready. It stays in ready for a burst
// and returns to idle at the end of the cycle.
always @ (posedge pci_clk)
begin
if (r_w_l && (state == first_data) && !data_read_l) begin
count = bkend_ad; // read address
if (!base_region0_l) begin
bkend_dat_reg = bk0[count[19:2]];
$display($time, " %m \t \t \t << Target reading bk0[%h] = %h >>", count, bkend_dat_reg);
end
else if (!base_region1_l) begin
bkend_dat_reg = bk1[count[19:2]];
$display($time, " %m \t \t \t << Target reading bk1[%h] = %h >>", count, bkend_dat_reg);
end
end
else if (r_w_l && (state == ready || state == data_stop || state == data_abort) && !data_read_l ) begin
count = count + 4; // burst read
if (!base_region0_l) begin
bkend_dat_reg = bk0[count[19:2]];
$display($time, " %m \t \t \t << Target reading bk0[%h] = %h >>", count, bkend_dat_reg);
end
else if (!base_region1_l) begin
bkend_dat_reg = bk1[count[19:2]];
$display($time, " %m \t \t \t << Target reading bk1[%h] = %h >>", count, bkend_dat_reg);
end
end
else if (!r_w_l && (state == first_data) && !data_write_l) begin
count = bkend_ad; // write address
if (!base_region0_l) begin
bk0[count[19:2]] = bkend_dat;
$display($time, " %m \t \t \t << Target writing bk0[%h] = %h >>", count, bkend_dat);
end
else if (!base_region1_l) begin
bk1[count[19:2]] = bkend_dat;
$display($time, " %m \t \t \t << Target writing bk1[%h] = %h >>", count, bkend_dat);
end
end
else if (!r_w_l && (state == ready || state == data_stop || state == data_abort) && !data_write_l ) begin
count = count + 4; // burst write
if (!base_region0_l) begin
bk0[count[19:2]] = bkend_dat;
$display($time, " %m \t \t \t << Target writing bk0[%h] = %h >>", count, bkend_dat);
end
else if (!base_region1_l) begin
bk1[count[19:2]] = bkend_dat;
$display($time, " %m \t \t \t << Target writing bk1[%h] = %h >>", count, bkend_dat);
end
end
end
// The following block is the behavioral state machine
// it controls the arbitration of all bkend control signals to
// the PCI target.
//
// On a normal read or write cycle the state machine will cycle from:
// idle -> first_data -> ready -> ready || idle
//
// If the cycle is a special cycle initiating a stop or an abort
// it will cycle from:
// idle -> first_data -> ready -> data_stop||data_abort -> data_stop||data_abort||idle
//
// On a retry it will cycle from:
// idle -> idle never responding which initiates a retry
//
// On an interruptit will cycle from:
// idle -> first_data -> ready -> ready || idle
//
always @ (posedge pci_clk or negedge pci_rst_l)
begin
if (pci_rst_l == 1'b0) begin
state = #1 idle;
ready_l = #1 1; // bkend is not ready
data_stop_l = #1 1'bZ;
bkend_int_l = #1 1;
bkend_abort_l = #1 1;
data_stop_flag = #1 0; //disabled
data_abort_flag = #1 0; //disabled
end
else begin
case (state)
idle: begin
if (!base_region0_l)
begin
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = #1 0; //disabled
data_abort_flag = #1 0; //disabled
end
else if (!base_region1_l && bkend_ad == 20'h000A0)
begin // initiate a Retry
state = #1 idle;
ready_l = #1 1; // bkend is NOT ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = #1 0; //disabled
data_abort_flag = #1 0; //disabled
end
else if (!base_region1_l && bkend_ad == 20'h000B0)
begin // initiate a data stop
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = #1 1; // flag a stop
data_abort_flag = #1 0; //disabled
end
else if (!base_region1_l && bkend_ad == 20'h000C0)
begin // initiate a data abort
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = #1 0; //disabled
data_abort_flag = #1 1; // flag an abort
end
else if (!base_region1_l && bkend_ad == 20'h000D0)
begin // initiate an interrupt
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_int_l = #1 0; // initiate an interupt
bkend_abort_l = #1 1;
data_stop_flag = #1 0; //disabled
data_abort_flag = #1 0; //disabled
end
else if (!base_region1_l && bkend_ad == 20'h000E0)
begin // disable the interrupt
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_int_l = #1 1; // disable the interupt
bkend_abort_l = #1 1;
data_stop_flag = #1 0; //disabled
data_abort_flag = #1 0; //disabled
end
else if (!base_region1_l)
begin // just a normal base_region1_l access
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = 0; //disabled
data_abort_flag = 0; //disabled
end
else
begin // stay in idle no accesses made
state = #1 idle;
ready_l = #1 1;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = 0; //disabled
data_abort_flag = 0; //disabled
end
end
first_data: begin
if (base_region0_l && base_region1_l) begin
$display(" %m \t \t This Shouldn't happen??!!!");
state = #1 idle;
ready_l = #1 1;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else if (!base_region0_l && (!data_write_l || !data_read_l)) begin
state = #1 ready;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else if (!base_region1_l && (!data_write_l || !data_read_l)) begin
state = #1 ready;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else begin // waiting to transfer first data
state = #1 first_data;
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
end
ready: begin
if (!base_region0_l) begin
state = #1 ready; // bursting
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else if (!base_region1_l && data_stop_flag) begin
state = #1 data_stop;
ready_l = #1 0;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else if (!base_region1_l && data_abort_flag) begin
state = #1 data_abort;
ready_l = #1 0;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else if (!base_region1_l) begin
state = #1 ready; // bursting
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
else begin // cycle is over
state = #1 idle;
ready_l = #1 1;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
end
end
data_stop: begin
if (!base_region1_l) begin
state = data_stop; // bursting & trying to stop
ready_l = #1 0; // bkend is ready
data_stop_l = #1 0; // initiate stop
bkend_abort_l = #1 1;
data_stop_flag = #1 0;
data_abort_flag = #1 0;
end
else begin // Target acknowledged stop & removed !base_region1_l
state = idle;
ready_l = #1 1;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1;
data_stop_flag = #1 0;
data_abort_flag = #1 0;
end
end
data_abort: begin
if (!base_region1_l) begin
state = data_abort; // bursting & trying to abort
ready_l = #1 0; // bkend is ready
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 0; // catostrophic failure abort!
data_stop_flag = #1 0; // disabled
data_abort_flag = #1 0; // disabled
end
else begin // Target acknowledged abort & removed !base_region1_l
state = idle;
ready_l = #1 1;
data_stop_l = #1 1'bZ;
bkend_abort_l = #1 1; // disable abort
data_stop_flag = #1 0; // disabled
data_abort_flag = #1 0; // disabled
end
end
default: begin
$display(" %m \t \t << Something is hosed, bkend SM going to idle >> ");
state = idle;
end
endcase
end
end
endmodule //of bkend_daemon
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -