summaryrefslogtreecommitdiff
path: root/rtl/gfx/gfx_mem.sv
blob: fbca2faa95fcc755e9dc676c9c6de3957f732466 (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
`include "gfx/gfx_defs.sv"

module gfx_mem
(
	input  logic          clk,
	                      rst_n,

	input  logic          mem_waitrequest,
	                      mem_readdatavalid,
	input  vram_word      mem_readdata,
	output vram_byte_addr mem_address,
	output logic          mem_read,
	                      mem_write,
	output vram_word      mem_writedata,

	input  vram_addr      host_address,
	input  logic          host_read,
	                      host_write,
	input  vram_word      host_writedata,
	output logic          host_waitrequest,
	                      host_readdatavalid,
	output vram_word      host_readdata,

	input  logic          rop_write,
	input  vram_word      rop_writedata,
	input  vram_addr      rop_address,
	output logic          rop_waitrequest,

	input  logic          fb_read,
	input  vram_addr      fb_address,
	output logic          fb_waitrequest,
	                      fb_readdatavalid,
	output vram_word      fb_readdata,

	input  logic          batch_read,
	input  vram_addr      batch_address,
	output logic          batch_waitrequest,
	                      batch_readdatavalid,
	output vram_word      batch_readdata,

	input  logic          fetch_read,
	input  vram_addr      fetch_address,
	output logic          fetch_waitrequest,
	                      fetch_readdatavalid,
	output vram_word      fetch_readdata
);

	// Este módulo es inaceptable, hay que reescribirlo

	logic mem_rw, trans_in_stall, trans_out_stall, in_ready, in_valid, skid_in_valid, out_ready,
	      any_readdatavalid, readdatavalid, dispatch_full, dispatch_put, mem_ready;

	vram_word any_readdata, readdata;
	logic[$clog2(`GFX_MEM_DISPATCH_DEPTH) - 1:0] next_put_ptr, pop_ptr, put_ptr;

	struct packed
	{
		logic fb,
		      host,
		      batch,
		      fetch;
	} dispatch_in, dispatch_out, dispatch_buf[`GFX_MEM_DISPATCH_DEPTH];

	struct packed
	{
		vram_addr address;
		logic     write,
		          fb_waitrequest,
		          host_waitrequest,
		          batch_waitrequest,
		          fetch_waitrequest;
		vram_word writedata;
	} trans_in, trans_out, trans_in_skid, trans_out_skid;

	assign mem_read = mem_rw && !trans_out_skid.write && !dispatch_full;
	assign mem_write = mem_rw && trans_out_skid.write;
	assign mem_address = {trans_out_skid.address, {`GFX_MEM_SUBWORD_BITS{1'b0}}};
	assign mem_writedata = trans_out_skid.writedata;

	assign fb_readdata = any_readdata;
	assign host_readdata = any_readdata;
	assign batch_readdata = any_readdata;
	assign fetch_readdata = any_readdata;

	assign fb_readdatavalid = any_readdatavalid && dispatch_out.fb;
	assign host_readdatavalid = any_readdatavalid && dispatch_out.host;
	assign batch_readdatavalid = any_readdatavalid && dispatch_out.batch;
	assign fetch_readdatavalid = any_readdatavalid && dispatch_out.fetch;

	assign dispatch_in.fb = !trans_out_skid.fb_waitrequest;
	assign dispatch_in.host = !trans_out_skid.host_waitrequest;
	assign dispatch_in.batch = !trans_out_skid.batch_waitrequest;
	assign dispatch_in.fetch = !trans_out_skid.fetch_waitrequest;

	assign in_valid = rop_write || fb_read || batch_read || fetch_read || host_read || host_write;
	assign mem_ready = !mem_waitrequest && (!dispatch_full || trans_out_skid.write);
	assign next_put_ptr = put_ptr + 1;
	assign dispatch_put = mem_ready && mem_rw && !trans_out_skid.write;
	assign dispatch_full = next_put_ptr == pop_ptr;

	/* Cerrar timing aquí no es tan fácil, debido al enrutamiento al el que
	 * necesariamente está sujeto este módulo (eg, VRAM y DAC están en
	 * posiciones fijas en los bordes de la FPGA y no pueden reacomodarse).
	 */

	gfx_skid_buf #(.WIDTH($bits(trans_in))) in_skid
	(
		.in(trans_in),
		.out(trans_in_skid),
		.stall(trans_in_stall),
		.*
	);

	gfx_skid_flow in_flow
	(
		.stall(trans_in_stall),
		.out_ready(out_ready),
		.out_valid(skid_in_valid),
		.*
	);

	gfx_pipes #(.WIDTH($bits(trans_out)), .DEPTH(`GFX_MEM_TRANS_DEPTH)) out_pipes
	(
		.in(trans_in_skid),
		.out(trans_out),
		.stall(trans_out_stall),
		.*
	);

	gfx_skid_buf #(.WIDTH($bits(trans_out))) out_skid
	(
		.in(trans_out),
		.out(trans_out_skid),
		.stall(trans_out_stall),
		.*
	);

	gfx_pipeline_flow #(.STAGES(`GFX_MEM_TRANS_DEPTH)) out_flow
	(
		.stall(trans_out_stall),
		.in_ready(out_ready),
		.in_valid(skid_in_valid),
		.out_ready(mem_ready),
		.out_valid(mem_rw),
		.*
	);

	gfx_pipes #(.WIDTH($bits(vram_word)), .DEPTH(`GFX_MEM_RESPONSE_DEPTH)) readdata_pipes
	(
		.in(mem_readdata),
		.out(readdata),
		.stall(0),
		.*
	);

	gfx_pipeline_flow #(.STAGES(`GFX_MEM_RESPONSE_DEPTH)) readdata_flow
	(
		.stall(),
		.in_ready(),
		.in_valid(mem_readdatavalid),
		.out_ready(1),
		.out_valid(readdatavalid),
		.*
	);

	always_comb begin
		fb_waitrequest = 1;
		rop_waitrequest = 1;
		host_waitrequest = 1;
		batch_waitrequest = 1;
		fetch_waitrequest = 1;

		trans_in.write = 0;
		trans_in.writedata = {($bits(trans_in.writedata)){1'bx}};

		if (fb_read) begin
			fb_waitrequest = !in_ready;
			trans_in.address = fb_address;
		end else if (batch_read) begin
			batch_waitrequest = !in_ready;
			trans_in.address = batch_address;
		end else if (rop_write) begin
			rop_waitrequest = !in_ready;

			trans_in.write = 1;
			trans_in.address = rop_address;
			trans_in.writedata = rop_writedata;
		end else if (fetch_read) begin
			fetch_waitrequest = !in_ready;
			trans_in.address = fetch_address;
		end else begin
			host_waitrequest = !in_ready;

			trans_in.write = host_write;
			trans_in.address = host_address;
			trans_in.writedata = host_writedata;
		end

		trans_in.fb_waitrequest = fb_waitrequest;
		trans_in.host_waitrequest = host_waitrequest;
		trans_in.batch_waitrequest = batch_waitrequest;
		trans_in.fetch_waitrequest = fetch_waitrequest;
	end

	always_ff @(posedge clk or negedge rst_n)
		if (!rst_n) begin
			pop_ptr <= 0;
			put_ptr <= 0;
		end else begin
			if (readdatavalid)
				pop_ptr <= pop_ptr + 1;

			if (dispatch_put)
				put_ptr <= next_put_ptr;
		end


	always_ff @(posedge clk) begin
		any_readdata <= readdata;
		any_readdatavalid <= readdatavalid;

		dispatch_out <= dispatch_buf[pop_ptr];

		if (dispatch_put)
			dispatch_buf[put_ptr] <= dispatch_in;
	end

endmodule