pi.v
5.36 KB
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// pi.v v1 Frank Berndt
// pi top level;
...
// memory address;
// must be 16-bit aligned for compatibility;
// loaded with pio write write;
// used for first dma block transfer to align;
// then increments in blocks of 128 bytes;
wire dma_addr_we; // write dma address;
wire dma_addr_ld; // load dma address;
wire dma_addr_inc; // increment dma address;
assign dma_addr_we = reg_write & ra_dma_addr;
assign dma_addr_ld = ~dma_conflict & dma_addr_we;
always @(posedge sysclk)
begin
if(dma_addr_ld)
dma_addr <= { pio_wdata[25:1], 1'b0 };
else if(dma_addr_inc)
dma_addr <= { dma_addr[25:7] + 1, 7'd0 };
end
// device address;
// virtual or physical address into device space;
// compatibility requires 16-bit alignment;
// however, bit 0 is needed for new functions;
wire dev_addr_we; // write device address;
wire dev_addr_ld; // load device address;
wire dev_addr_inc; // increment device address;
assign dev_addr_we = reg_write & ra_dev_addr;
assign dev_addr_ld = ~dma_conflict & dev_addr_we;
always @(posedge sysclk)
begin
if(dev_addr_ld)
dev_addr <= pio_wdata[29:0];
else if(io_write)
dev_addr <= pio_addr;
else if(dev_addr_inc)
dev_addr[29:3] <= dev_addr[29:3] + 1;
end
// dma length;
// writing the dma length registers starts the dma;
// starting a dma through PI_DMA_READ triggers error interrupt;
// it is up to software to emulate the write;
// one clock later, add lower addres bits for # of dw;
// decremented by buffer dma for each double-word;
// do not start dma when dma_len is 0, but issue done;
wire dma_len_we; // write to dma length;
wire dma_len_ld; // load dma_len;
wire dma_proc; // start write dma process;
wire dma_trap; // trap read dma;
reg dma_kick; // kick dma;
wire dma_len_dec; // decrement dma length;
wire dma_len_nw0; // # of dw is 0;
reg dma_len_zero; // dma length is 0;
wire [23:0] dma_off; // lower byte offset;
assign dma_len_we = reg_write & ra_dma_len;
assign dma_len_ld = ~dma_conflict & dma_len_we;
assign dma_off = { 21'd0, dma_addr[2:1], 1'b0 };
assign dma_len_nw0 = (dma_len[23:3] == 21'd0);
always @(posedge sysclk)
begin
dma_kick <= dma_len_ld;
if(dma_len_ld) begin
dma_read <= ra_dma_read | ra_bread;
dma_rwb <= ra_bread | ra_bwrite;
end
if(dma_len_ld)
dma_len <= pio_wdata[23:0];
else if(dma_kick)
dma_len <= dma_len + dma_off;
else if(dma_len_dec)
dma_len[23:3] <= dma_len[23:3] - 1;
if(io_kick)
dma_len_zero <= 1'b0;
else if(dma_kick)
dma_len_zero <= &dma_len;
else if(dma_len_dec)
dma_len_zero <= dma_len_nw0;
end
....
// dma burst length;
// first burst aligns to 128-byte block;
// a number of full 128-byte bursts may follow;
// last burst moves the remaining bytes;
wire bdma_ge128; // dma_len >= 128;
wire [6:3] bdma_dwib; // # of dw in current burst;
reg bdma_fill; // fill current burst;
reg [6:0] bdma_len; // burst dma length;
assign bdma_ge128 = |dma_len[23:7];
assign bdma_dwib = ~dma_addr[6:3];
always @(posedge sysclk)
begin
bdma_fill <= bdma_ge128 | (dma_len[6:3] > bdma_dwib);
bdma_len <= bdma_fill? { bdma_dwib, 3'b111 } : dma_len[6:0];
end
// request dbus dma;
reg bdma_aesp; // aesp requests one burst dma;
wire bdma_req; // dma burst request;
wire bdma_cyc_clr; // clear bdma busy;
reg bdma_cyc; // bdma busy;
wire bdma_req_clr; // clear dma request;
reg dma_request; // dma request;
reg bdma_ack; // burst dma ack;
reg bdma_ack2;
reg bdma_ack3;
assign bdma_cyc_clr = dma_stop | bdma_ack3;
assign bdma_req_clr = dma_stop | dma_grant;
assign bdma_req = dma_busy & ~dma_len_zero & ~bdma_cyc & (bdma_aesp | bdma_busy);
always @(posedge sysclk)
begin
bdma_cyc <= ~bdma_cyc_clr & (bdma_cyc | bdma_req);
dma_request <= ~bdma_req_clr & (dma_request | bdma_req);
bdma_ack <= dma_last;
bdma_ack2 <= bdma_ack;
bdma_ack3 <= bdma_ack2;
end
// burst dma control;
reg bdma_dph; // burst dma phase;
wire bdma_val; // burst dma data valid;
reg [1:0] bdma_dval; // delayed valid;
wire dbus_shr; // data right shift;
always @(posedge sysclk)
begin
bdma_dph <= bdma_cyc & ~dma_last & (bdma_dph | dma_start);
bdma_dval <= { bdma_dval[0], bdma_val };
end
assign bdma_val = dma_start | bdma_dph;
assign dma_len_dec = bdma_dval[0];
assign dma_addr_inc = bdma_ack;
assign dev_addr_inc = bdma_dval[0];
....
// aes data count;
// amount of data that has passed the aes process;
// kick burst dma when enough data to fill a dma cycle;
wire dev_off_nz; // dev_addr not aligned to aes blocks;
reg [10:1] aesp_cnt; // data count;
wire aesp_cnt_inc; // aes done with another double-word;
wire aesp_cnt_dec; // bdma moved another word;
assign dev_off_nz = (dev_addr[3:1] != 3'd0);
always @(posedge sysclk)
begin
if(proc_start) begin
aesp_cnt[10:4] <= {7{dev_off_nz}};
aesp_cnt[3:1] <= (~dev_addr[3:1] + 1);
end if(aesp_cnt_inc & ~aesp_cnt_dec)
aesp_cnt <= aesp_cnt + 4;
else if(aesp_cnt_dec & ~aesp_cnt_inc)
aesp_cnt <= aesp_cnt - 4;
bdma_aesp <= proc_busy & ~aesp_cnt[10]
& (aesp_cnt[9:1] > { 3'd0, bdma_len[6:1] });
end
assign aesp_cnt_inc = aes_dw;
assign aesp_cnt_dec = bdma_dval[0];
assign proc_rblk = ~aesp_cnt[10] & |aesp_cnt[9:8];
// assertions;
// synopsys translate_off
always @(posedge sysclk)
begin
if(proc_busy & aesp_cnt[10] & aesp_cnt_dec)
$display("ERROR: %t: %M: bdma overran aes", $time);
end
// synopsys translate_on
endmodule