-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapb_slave.sv
122 lines (98 loc) · 4.15 KB
/
apb_slave.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
module apb_slave # (
parameter ADDR_WIDTH = 32, //! Address width parameter
parameter DATA_WIDTH = 8 //! Data width parameter
) (
// Global Signals
input PCLK, //! General input clock
input PPRESETn, //! General Reset singal
// Slave response signals
output logic PREADY_o, //! Ready signal from slave (1 = ready, 0 = not ready)
// Control signals from Master
input PWRITE_i, //! Write control signal (1 = write, 0 = read)
input PSEL_i, //! Peripheral select signal (asserted when this slave is selected)
input PENABLE_i, //! Enable signal (asserted during the active transfer phase)
// Address and data buses
input [ADDR_WIDTH -1 :0] PADDR_i, //! Address sent to slave from master
input [DATA_WIDTH -1 :0] PWDATA_i, //! Data received from master during a write operation
output logic [DATA_WIDTH -1 :0] PRDATA_o, //! Data sent to master during a read operation
output PSLVERR_o
);
localparam mem_depth = 16;
logic [DATA_WIDTH-1 :0] mem [0:mem_depth-1];
bit add_err, addv_err,data_err;
//----------------------------------------------
//! State Encoding
//----------------------------------------------
typedef enum logic [1:0] {
IDLE = 2'b01,
WRTE = 2'b10,
READ = 2'b11
} apb_state_t;
apb_state_t current_state, next_state;
//! This `always_ff` block handles the state transition logic for the FSM.
//! - On reset (`PPRESETn` deasserted), the FSM enters the `IDLE` state.
//! - On each rising edge of `PCLK`, the current state updates to the next state.
always_ff @ (posedge PCLK or negedge PPRESETn) begin : state_transition
if (!PPRESETn)
current_state <= IDLE;
else
current_state <= next_state;
end
//! This `always_comb` block implements the combinational logic for an APB slave state machine.
//! It determines the next state (`next_state`) and generates outputs (`PREADY_o`, `PRDATA_o`)
//! based on the current state (`current_state`) and inputs (`PSEL_i`, `PWRITE_i`, `PENABLE_i`, etc.).
//!
//! States:
//! - `IDLE`: Waits for a transaction. Transitions to `WRTE` (write) or `READ` (read) if `PSEL_i` is asserted.
//! - `WRTE`: Completes a write operation if `PSEL_i` and `PENABLE_i` are asserted.
//! - `READ`: Completes a read operation if `PSEL_i` and `PENABLE_i` are asserted, outputting data from `mem`.
//!
//! Outputs:
//! - `PREADY_o`: Asserted to indicate the slave is ready.
//! - `PRDATA_o`: Outputs read data during a read operation.
//!
//! Notes:
//! - Memory write logic should be moved to an `always_ff` block.
//! - Errors (`add_err`, `addv_err`, `data_err`) prevent invalid memory access.
always_comb begin : apb_slave_comb_logic
// Default assignments
PREADY_o = 1'b0;
PRDATA_o = 'b0;
next_state = current_state; // Default to current state
case (current_state)
IDLE: begin
if (PSEL_i) begin
next_state = (PWRITE_i) ? WRTE : READ;
end else begin
next_state = IDLE;
end
end
WRTE: begin
if (PSEL_i && PENABLE_i) begin
next_state = IDLE;
PREADY_o = 1'b1;
// Memory write logic should be moved to an always_ff block
end
end
READ: begin
if (PSEL_i && PENABLE_i) begin
next_state = IDLE;
PREADY_o = 1'b1;
if (!add_err && !addv_err && !data_err)
PRDATA_o = mem[PADDR_i]; // Ensure PADDR_i is within valid range
end
end
default: begin
next_state = IDLE;
end
endcase
end : apb_slave_comb_logic
// Chekcing valid values of address
logic av_t = (PADDR_i >= 0)? 1'b0 : 1'b1;
// Chekcing valid values of data
logic dv_t = (PWDATA_i >= 0)? 1'b0 : 1'b1;
assign add_err = ((next_state[1]) && (PADDR_i >= mem_depth))? 1'b1 : 1'b0;
assign addv_err = ( next_state[1])? av_t : 1'b0;
assign data_err = ( next_state[1])? dv_t : 1'b0;
assign PSLVERR = (PSEL_i && PENABLE_i)? (add_err || addv_err || data_err) : 1'b0;
endmodule