summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/migsdram.v
blob: c1671c86a4933a629c62136730351105575491d4 (plain)
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
////////////////////////////////////////////////////////////////////////////////
//
// Filename: 	migsdram.v
// {{{
// Project:	WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose:	This file isn't really a part of the synthesis implementation 
//		of the wb2axip project itself, but rather it is an example
//	of how the wb2axip project can be used to connect a MIG generated
//	IP component.
//
//	This implementation depends upon the existence of a MIG generated
//	core, named "mig_axis", and illustrates how such a core might be
//	connected to the wbm2axip bridge.  Specific options of the mig_axis
//	setup include 6 identifier bits, and a full-sized bus width of 128
//	bits.   These two settings are both appropriate for driving a DDR3
//	memory (whose minimum transfer size is 128 bits), but may need to be
//	adjusted to support other memories.
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
// }}}
// Copyright (C) 2015-2024, Gisselquist Technology, LLC
// {{{
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License").  You may not use this project,
// or this file, except in compliance with the License.  You may obtain a copy
// of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations
// under the License.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype	none
// }}}
module	migsdram(i_clk, i_clk_200mhz, o_sys_clk, i_rst, o_sys_reset,
	// Wishbone components
		i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
		o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
	// SDRAM connections
		o_ddr_ck_p, o_ddr_ck_n,
		o_ddr_reset_n, o_ddr_cke,
		o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
		o_ddr_ba, o_ddr_addr, 
		o_ddr_odt, o_ddr_dm,
		io_ddr_dqs_p, io_ddr_dqs_n,
		io_ddr_data
	);
	parameter	DDRWIDTH = 16, WBDATAWIDTH=32;
	parameter	AXIDWIDTH = 6;
	// The SDRAM address bits (RAMABITS) are a touch more difficult to work
	// out.  Here we leave them as a fixed parameter, but there are 
	// consequences to this.  Specifically, the wishbone data width, the
	// wishbone address width, and this number have interactions not
	// well captured here.
	parameter	RAMABITS = 28;
	// All DDR3 memories have 8 timeslots.  This, if the DDR3 memory
	// has 16 bits to it (as above), the entire transaction must take
	// AXIWIDTH bits ...
	localparam	AXIWIDTH= DDRWIDTH *8;
	localparam	DW=WBDATAWIDTH;
	localparam	AW=(WBDATAWIDTH==32)? RAMABITS-2
				:((WBDATAWIDTH==64) ? RAMABITS-3
				:((WBDATAWIDTH==128) ? RAMABITS-4
				: RAMABITS-5)); // (WBDATAWIDTH==256)
	localparam	SELW= (WBDATAWIDTH/8);
	//
	input	wire		i_clk, i_clk_200mhz, i_rst;
	output	wire		o_sys_clk;
	output	reg		o_sys_reset;
	//
	input	wire		i_wb_cyc, i_wb_stb, i_wb_we;
	input	wire	[(AW-1):0]	i_wb_addr;
	input	wire	[(DW-1):0]	i_wb_data;
	input	wire	[(SELW-1):0]	i_wb_sel;
	output	wire			o_wb_ack, o_wb_stall;
	output	wire	[(DW-1):0]	o_wb_data;
	output	wire			o_wb_err;
	//
	output	wire	[0:0]		o_ddr_ck_p, o_ddr_ck_n;
	output	wire	[0:0]		o_ddr_cke;
	output	wire			o_ddr_reset_n,
					o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n;
	output	wire	[0:0]			o_ddr_cs_n;
	output	wire	[2:0]			o_ddr_ba;
	output	wire	[13:0]			o_ddr_addr;
	output	wire	[0:0]			o_ddr_odt;
	output	wire	[(DDRWIDTH/8-1):0]	o_ddr_dm;
	inout	wire	[1:0]			io_ddr_dqs_p, io_ddr_dqs_n;
	inout	wire	[(DDRWIDTH-1):0]	io_ddr_data;


`define	SDRAM_ACCESS
`ifdef	SDRAM_ACCESS

	wire	aresetn;
	assign	aresetn = 1'b1; // Never reset

	// Write address channel
	wire	[(AXIDWIDTH-1):0]	s_axi_awid;
	wire	[(RAMABITS-1):0]	s_axi_awaddr;
	wire	[7:0]			s_axi_awlen;
	wire	[2:0]			s_axi_awsize;
	wire	[1:0]			s_axi_awburst;
	wire	[0:0]			s_axi_awlock;
	wire	[3:0]			s_axi_awcache;
	wire	[2:0]			s_axi_awprot;
	wire	[3:0]			s_axi_awqos;
	wire				s_axi_awvalid;
	wire				s_axi_awready;
	// Writei data channel
	wire	[(AXIWIDTH-1):0]	s_axi_wdata;
	wire	[(AXIWIDTH/8-1):0]	s_axi_wstrb;
	wire				s_axi_wlast, s_axi_wvalid, s_axi_wready;
	// Write response channel
	wire				s_axi_bready;
	wire	[(AXIDWIDTH-1):0]	s_axi_bid;
	wire	[1:0]			s_axi_bresp;
	wire				s_axi_bvalid;

	// Read address channel
	wire	[(AXIDWIDTH-1):0]	s_axi_arid;
	wire	[(RAMABITS-1):0]	s_axi_araddr;
	wire	[7:0]			s_axi_arlen;
	wire	[2:0]			s_axi_arsize;
	wire	[1:0]			s_axi_arburst;
	wire	[0:0]			s_axi_arlock;
	wire	[3:0]			s_axi_arcache;
	wire	[2:0]			s_axi_arprot;
	wire	[3:0]			s_axi_arqos;
	wire				s_axi_arvalid;
	wire				s_axi_arready;
	// Read response/data channel
	wire	[(AXIDWIDTH-1):0]	s_axi_rid;
	wire	[(AXIWIDTH-1):0]	s_axi_rdata;
	wire	[1:0]			s_axi_rresp;
	wire				s_axi_rlast;
	wire				s_axi_rvalid;
	wire				s_axi_rready;

	// Other wires ...
	wire		init_calib_complete, mmcm_locked;
	wire		app_sr_active, app_ref_ack, app_zq_ack;
	wire		app_sr_req, app_ref_req, app_zq_req;
	wire		w_sys_reset;
	wire	[11:0]	w_device_temp;


	mig_axis	mig_sdram(
		.ddr3_ck_p(o_ddr_ck_p),		.ddr3_ck_n(o_ddr_ck_n),
		.ddr3_reset_n(o_ddr_reset_n),	.ddr3_cke(o_ddr_cke),
		.ddr3_cs_n(o_ddr_cs_n),		.ddr3_ras_n(o_ddr_ras_n),
		.ddr3_we_n(o_ddr_we_n),		.ddr3_cas_n(o_ddr_cas_n),
		.ddr3_ba(o_ddr_ba),		.ddr3_addr(o_ddr_addr),
		.ddr3_odt(o_ddr_odt),
		.ddr3_dqs_p(io_ddr_dqs_p),	.ddr3_dqs_n(io_ddr_dqs_n),
		.ddr3_dq(io_ddr_data),		.ddr3_dm(o_ddr_dm),
		//
		.sys_clk_i(i_clk),
		.clk_ref_i(i_clk_200mhz),
		.ui_clk(o_sys_clk),
		.ui_clk_sync_rst(w_sys_reset),
		.mmcm_locked(mmcm_locked),
		.aresetn(aresetn),
		.app_sr_req(1'b0),
		.app_ref_req(1'b0),
		.app_zq_req(1'b0),
		.app_sr_active(app_sr_active),
		.app_ref_ack(app_ref_ack),
		.app_zq_ack(app_zq_ack),
		//
		.s_axi_awid(s_axi_awid),	.s_axi_awaddr(s_axi_awaddr),
		.s_axi_awlen(s_axi_awlen),	.s_axi_awsize(s_axi_awsize),
		.s_axi_awburst(s_axi_awburst),	.s_axi_awlock(s_axi_awlock),
		.s_axi_awcache(s_axi_awcache),	.s_axi_awprot(s_axi_awprot),
		.s_axi_awqos(s_axi_awqos),	.s_axi_awvalid(s_axi_awvalid),
		.s_axi_awready(s_axi_awready),
		//
		.s_axi_wready(	s_axi_wready),
		.s_axi_wdata(	s_axi_wdata),
		.s_axi_wstrb(	s_axi_wstrb),
		.s_axi_wlast(	s_axi_wlast),
		.s_axi_wvalid(	s_axi_wvalid),
		//
		.s_axi_bready(s_axi_bready),	.s_axi_bid(s_axi_bid),
		.s_axi_bresp(s_axi_bresp),	.s_axi_bvalid(s_axi_bvalid),
		//
		.s_axi_arid(s_axi_arid),	.s_axi_araddr(s_axi_araddr),
		.s_axi_arlen(s_axi_arlen),	.s_axi_arsize(s_axi_arsize),
		.s_axi_arburst(s_axi_arburst),	.s_axi_arlock(s_axi_arlock),
		.s_axi_arcache(s_axi_arcache),	.s_axi_arprot(s_axi_arprot),
		.s_axi_arqos(s_axi_arqos),	.s_axi_arvalid(s_axi_arvalid),
		.s_axi_arready(s_axi_arready),
		// 
		.s_axi_rready(s_axi_rready),	.s_axi_rid(s_axi_rid),
		.s_axi_rdata(s_axi_rdata),	.s_axi_rresp(s_axi_rresp),
		.s_axi_rlast(s_axi_rlast),	.s_axi_rvalid(s_axi_rvalid),
		.init_calib_complete(init_calib_complete),
		.sys_rst(i_rst),
		.device_temp(w_device_temp)
		);

	wbm2axisp	#( 
			.C_AXI_ID_WIDTH(AXIDWIDTH),
			.C_AXI_DATA_WIDTH(AXIWIDTH),
			.C_AXI_ADDR_WIDTH(RAMABITS),
			.AW(AW), .DW(DW)
			)
			bus_translator(
				.i_clk(o_sys_clk),
				// .i_reset(i_rst), // internally unused
				// Write address channel signals
				.o_axi_awvalid(	s_axi_awvalid), 
				.i_axi_awready(	s_axi_awready), 
				.o_axi_awid(	s_axi_awid), 
				.o_axi_awaddr(	s_axi_awaddr), 
				.o_axi_awlen(	s_axi_awlen), 
				.o_axi_awsize(	s_axi_awsize), 
				.o_axi_awburst(	s_axi_awburst), 
				.o_axi_awlock(	s_axi_awlock), 
				.o_axi_awcache(	s_axi_awcache), 
				.o_axi_awprot(	s_axi_awprot),  // s_axi_awqos
				.o_axi_awqos(	s_axi_awqos),  // s_axi_awqos
			//
				.o_axi_wvalid(	s_axi_wvalid),
				.i_axi_wready(	s_axi_wready),
				.o_axi_wdata(	s_axi_wdata),
				.o_axi_wstrb(	s_axi_wstrb),
				.o_axi_wlast(	s_axi_wlast),
			//
				.i_axi_bvalid(	s_axi_bvalid),
				.o_axi_bready(	s_axi_bready),
				.i_axi_bid(	s_axi_bid),
				.i_axi_bresp(	s_axi_bresp),
			//
				.o_axi_arvalid(	s_axi_arvalid),
				.i_axi_arready(	s_axi_arready),
				.o_axi_arid(	s_axi_arid),
				.o_axi_araddr(	s_axi_araddr),
				.o_axi_arlen(	s_axi_arlen),
				.o_axi_arsize(	s_axi_arsize),
				.o_axi_arburst(	s_axi_arburst),
				.o_axi_arlock(	s_axi_arlock),
				.o_axi_arcache(	s_axi_arcache),
				.o_axi_arprot(	s_axi_arprot),
				.o_axi_arqos(	s_axi_arqos),
			//
				.i_axi_rvalid(	s_axi_rvalid),
				.o_axi_rready(	s_axi_rready),
				.i_axi_rid(	s_axi_rid),
				.i_axi_rdata(	s_axi_rdata),
				.i_axi_rresp(	s_axi_rresp),
				.i_axi_rlast(	s_axi_rlast),
			//
				.i_wb_cyc(	i_wb_cyc),
				.i_wb_stb(	i_wb_stb),
				.i_wb_we(	i_wb_we),
				.i_wb_addr(	i_wb_addr),
				.i_wb_data(	i_wb_data),
				.i_wb_sel(	i_wb_sel),
			//
				.o_wb_stall(	o_wb_stall),
				.o_wb_ack(	o_wb_ack),
				.o_wb_data(	o_wb_data),
				.o_wb_err(	o_wb_err)
		);

	// Convert from active low to active high, *and* hold the system in
	// reset until the memory comes up.	
	initial	o_sys_reset = 1'b1;
	always @(posedge o_sys_clk)
		o_sys_reset <= (!w_sys_reset)
				||(!init_calib_complete)
				||(!mmcm_locked);
`else
	BUFG	sysclk(i_clk, o_sys_clk);
	initial	o_sys_reset <= 1'b1;
	always @(posedge i_clk)
		o_sys_reset <= 1'b1;

	OBUFDS ckobuf(.I(i_clk), .O(o_ddr_ck_p), .OB(o_ddr_ck_n));

	assign	o_ddr_reset_n	= 1'b0;
	assign	o_ddr_cke[0]	= 1'b0;
	assign	o_ddr_cs_n[0]	= 1'b1;
	assign	o_ddr_cas_n	= 1'b1;
	assign	o_ddr_ras_n	= 1'b1;
	assign	o_ddr_we_n	= 1'b1;
	assign	o_ddr_ba	= 3'h0;
	assign	o_ddr_addr	= 14'h00;
	assign	o_ddr_dm	= 2'b00;
	assign	io_ddr_data	= 16'h0;

	OBUFDS	dqsbufa(.I(i_clk), .O(io_ddr_dqs_p[1]), .OB(io_ddr_dqs_n[1]));
	OBUFDS	dqsbufb(.I(i_clk), .O(io_ddr_dqs_p[0]), .OB(io_ddr_dqs_n[0]));

`endif

endmodule
`ifndef	YOSYS
`default_nettype wire
`endif