📄 pci_master32_sm.v
字号:
latency_timer <= #`FF_DELAY latency_timer - 1'b1 ;
end
// master abort indicators - when decode time out occurres and still no target response is received
wire do_master_abort = decode_to && pci_trdy_in && pci_stop_in && pci_devsel_in ;
reg mabort1 ;
always@(posedge reset_in or posedge clk_in)
begin
if (reset_in)
mabort1 <= #`FF_DELAY 1'b0 ;
else
mabort1 <= #`FF_DELAY do_master_abort ;
end
reg mabort2 ;
always@(posedge reset_in or posedge clk_in)
begin
if ( reset_in )
mabort2 <= #`FF_DELAY 1'b0 ;
else
mabort2 <= #`FF_DELAY mabort1 ;
end
// master abort is only asserted for one clock cycle
assign mabort_out = mabort1 && ~mabort2 ;
// register indicating when master should do timeout termination (latency timer expires)
reg timeout ;
always@(posedge reset_in or posedge clk_in)
begin
if (reset_in)
timeout <= #`FF_DELAY 1'b0 ;
else
timeout <= #`FF_DELAY (latency_time_out && ~pci_frame_out_in && pci_gnt_in || timeout ) && ~wait_out ;
end
wire timeout_termination = sm_turn_arround && timeout && pci_stop_reg_in ;
// frame control logic
// frame is forced to 0 (active) when state machine is in idle state, since only possible next state is address state which always drives frame active
wire force_frame = ~sm_idle ;
// slow signal for frame calculated from various registers in the core
wire slow_frame = last_in || (latency_time_out && pci_gnt_in) || (next_last_in && sm_data_phases) || mabort1 ;
// critical timing frame logic in separate module - some combinations of target signals force frame to inactive state immediately after sampled asserted
// (STOP)
pci_frame_crit frame_iob_feed
(
.pci_frame_out (pci_frame_out),
.force_frame_in (force_frame),
.slow_frame_in (slow_frame),
.pci_stop_in (pci_stop_in)
) ;
// frame IOB flip flop's clock enable signal
// slow clock enable - calculated from internal - non critical paths
wire frame_load_slow = sm_idle || sm_address || mabort1 ;
// critical clock enable for frame IOB in separate module - target response signals actually allow frame value change - critical timing
pci_frame_load_crit frame_iob_ce
(
.pci_frame_load_out (pci_frame_load_out),
.sm_data_phases_in (sm_data_phases),
.frame_load_slow_in (frame_load_slow),
.pci_trdy_in (pci_trdy_in),
.pci_stop_in (pci_stop_in)
) ;
// IRDY driving
// non critical path for IRDY calculation
wire irdy_slow = pci_frame_out_in && mabort1 || mabort2 ;
// critical path in separate module
pci_irdy_out_crit irdy_iob_feed
(
.pci_irdy_out (pci_irdy_out),
.irdy_slow_in (irdy_slow),
.pci_frame_out_in (pci_frame_out_in),
.pci_trdy_in (pci_trdy_in),
.pci_stop_in (pci_stop_in)
) ;
// transfer FF indicator - when first transfer occurs it is set to 1 so backend can distinguish between disconnects and retries.
wire sm_transfer = sm_data_phases ;
reg transfer ;
wire transfer_input = sm_transfer && (~(pci_trdy_in || pci_devsel_in) || transfer) ;
always@(posedge clk_in or posedge reset_in)
begin
if (reset_in)
transfer <= #`FF_DELAY 1'b0 ;
else
transfer <= #`FF_DELAY transfer_input ;
end
assign first_out = ~transfer ;
// fast transfer status output - it's only negated target ready, since wait indicator qualifies valid transfer
assign wtransfer_out = ~pci_trdy_in ;
// registered transfer status output - calculated from registered target response inputs
assign rtransfer_out = ~(pci_trdy_reg_in || pci_devsel_reg_in) ;
// registered error status - calculated from registered target response inputs
assign rerror_out = (~pci_stop_reg_in && pci_devsel_reg_in) ;
// retry is signalled to backend depending on registered target response or when latency timer expires
assign retry_out = timeout_termination || (~pci_stop_reg_in && ~pci_devsel_reg_in) ;
// AD output flip flops' clock enable
// new data is loaded to AD outputs whenever state machine is idle, bus was granted and bus is in idle state or
// when address phase is about to be finished
wire ad_load_slow = sm_address ;
wire ad_load_on_grant = sm_idle && pci_frame_in && pci_irdy_in ;
pci_mas_ad_load_crit mas_ad_load_feed
(
.ad_load_out (ad_load_out),
.ad_load_in (ad_load_slow),
.ad_load_on_grant_in (ad_load_on_grant),
.pci_gnt_in (pci_gnt_in)
);
// next data loading is allowed when state machine is in transfer state and operation is a write
assign ad_load_on_transfer_out = sm_data_phases && do_write ;
// request for a bus is issued anytime when backend is requesting a transaction and state machine is in idle state
assign pci_req_out = ~(req_in && sm_idle) ;
// change state signal is actually clock enable for state register
// Non critical path for state change enable:
// state is always changed when:
// - address phase is finishing
// - state machine is in turn arround state
// - state machine is in transfer state and master abort termination is in progress
wire ch_state_slow = sm_address || sm_turn_arround || sm_data_phases && ( pci_frame_out_in && mabort1 || mabort2 ) ;
// a bit more critical change state enable is calculated with GNT signal
wire ch_state_med = ch_state_slow || sm_idle && u_have_pci_bus && req_in && rdy_in ;
// most critical change state enable - calculated from target response signals
pci_mas_ch_state_crit state_machine_ce
(
.change_state_out (change_state),
.ch_state_med_in (ch_state_med),
.sm_data_phases_in (sm_data_phases),
.pci_trdy_in (pci_trdy_in),
.pci_stop_in (pci_stop_in)
) ;
// ad enable driving
// also divided in several categories - from less critical to most critical in separate module
//wire ad_en_slowest = do_write && (sm_address || sm_data_phases && ~pci_frame_out_in) ;
//wire ad_en_on_grant = sm_idle && pci_frame_in && pci_irdy_in || sm_turn_arround ;
//wire ad_en_slow = ad_en_on_grant && ~pci_gnt_in || ad_en_slowest ;
//wire ad_en_keep = sm_data_phases && do_write && (pci_frame_out_in && ~mabort1 && ~mabort2) ;
wire ad_en_slow = do_write && ( sm_address || ( sm_data_phases && !( ( pci_frame_out_in && mabort1 ) || mabort2 ) ) ) ;
wire ad_en_on_grant = ( sm_idle && pci_frame_in && pci_irdy_in ) || sm_turn_arround ;
// critical timing ad enable - calculated from grant input
pci_mas_ad_en_crit ad_iob_oe_feed
(
.pci_ad_en_out (pci_ad_en_out),
.ad_en_slow_in (ad_en_slow),
.ad_en_on_grant_in (ad_en_on_grant),
.pci_gnt_in (pci_gnt_in)
) ;
// cbe enable driving
wire cbe_en_on_grant = sm_idle && pci_frame_in && pci_irdy_in || sm_turn_arround ;
wire cbe_en_slow = cbe_en_on_grant && ~pci_gnt_in || sm_address || sm_data_phases && ~pci_frame_out_in ;
wire cbe_en_keep = sm_data_phases && pci_frame_out_in && ~mabort1 && ~mabort2 ;
// most critical cbe enable in separate module - calculated with most critical target inputs
pci_cbe_en_crit cbe_iob_feed
(
.pci_cbe_en_out (pci_cbe_en_out),
.cbe_en_slow_in (cbe_en_slow),
.cbe_en_keep_in (cbe_en_keep),
.pci_stop_in (pci_stop_in),
.pci_trdy_in (pci_trdy_in)
) ;
// IRDY enable is equal to FRAME enable delayed for one clock
assign pci_irdy_en_out = pci_frame_en_in ;
// frame enable driving - sometimes it's calculated from non critical paths
wire frame_en_slow = (sm_idle && u_have_pci_bus && req_in && rdy_in) || sm_address || (sm_data_phases && ~pci_frame_out_in) ;
wire frame_en_keep = sm_data_phases && pci_frame_out_in && ~mabort1 && ~mabort2 ;
// most critical frame enable - calculated from heavily constrained target inputs in separate module
pci_frame_en_crit frame_iob_en_feed
(
.pci_frame_en_out (pci_frame_en_out),
.frame_en_slow_in (frame_en_slow),
.frame_en_keep_in (frame_en_keep),
.pci_stop_in (pci_stop_in),
.pci_trdy_in (pci_trdy_in)
) ;
// state machine next state definitions
always@(
cur_state or
do_write or
pci_frame_out_in
)
begin
// default values for state machine outputs
wait_out = 1'b1 ;
wdata_selector = SEL_ADDR_BC ;
sm_idle = 1'b0 ;
sm_address = 1'b0 ;
sm_data_phases = 1'b0 ;
sm_turn_arround = 1'b0 ;
case ( cur_state )
S_IDLE: begin
// indicate the state
sm_idle = 1'b1 ;
// assign next state - only possible is address - if state machine is supposed to stay in idle state
// outside signals disable the clock
next_state = S_ADDRESS ;
wdata_selector = SEL_DATA_BE ;
end
S_ADDRESS: begin
// indicate the state
sm_address = 1'b1 ;
// select appropriate data/be for outputs
wdata_selector = SEL_NEXT_DATA_BE ;
// only possible next state is transfer state
next_state = S_TRANSFER ;
end
S_TRANSFER: begin
// during transfers wait indicator is inactive - all status signals are now valid
wait_out = 1'b0 ;
// indicate the state
sm_data_phases = 1'b1 ;
// select appropriate data/be for outputs
wdata_selector = SEL_NEXT_DATA_BE ;
if ( pci_frame_out_in )
begin
// when frame is inactive next state will be turn arround
next_state = S_TA_END ;
end
else
// while frame is active state cannot be anything else then transfer
next_state = S_TRANSFER ;
end
S_TA_END: begin
// wait is still inactive because of registered statuses
wait_out = 1'b0 ;
// indicate the state
sm_turn_arround = 1'b1 ;
// next state is always idle
next_state = S_IDLE ;
end
default: next_state = S_IDLE ;
endcase
end
// ad and cbe lines multiplexer for write data
reg [1:0] rdata_selector ;
always@(posedge clk_in or posedge reset_in)
begin
if ( reset_in )
rdata_selector <= #`FF_DELAY SEL_ADDR_BC ;
else
if ( change_state )
rdata_selector <= #`FF_DELAY wdata_selector ;
end
always@(rdata_selector or address_in or bc_in or data_in or be_in or next_data_in or next_be_in)
begin
case ( rdata_selector )
SEL_ADDR_BC: begin
pci_ad_out = address_in ;
pci_cbe_out = bc_in ;
end
SEL_DATA_BE: begin
pci_ad_out = data_in ;
pci_cbe_out = be_in ;
end
SEL_NEXT_DATA_BE,
2'b10: begin
pci_ad_out = next_data_in ;
pci_cbe_out = next_be_in ;
end
endcase
end
// data output mux for reads
always@(mabort_out or pci_ad_reg_in)
begin
if ( mabort_out )
data_out = 32'hFFFF_FFFF ;
else
data_out = pci_ad_reg_in ;
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -