-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathgpu.v
128 lines (117 loc) · 3.63 KB
/
gpu.v
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
`default_nettype none
module gpu(input wire clk,
input wire draw,
input wire [11:0] addr,
input wire [3:0] lines,
input wire [5:0] x,
input wire [4:0] y,
output wire busy,
output reg collision,
output reg mem_read,
output reg [11:0] mem_read_idx,
input wire [7:0] mem_read_byte,
input wire mem_read_ack,
output reg mem_write,
output reg [11:0] mem_write_idx,
output reg [7:0] mem_write_byte);
localparam WIDTH = 8;
localparam
STATE_IDLE = 0,
STATE_LOAD_SPRITE = 1,
STATE_LOAD_MEM_LEFT = 2,
STATE_STORE_MEM_LEFT = 3,
STATE_LOAD_MEM_RIGHT = 4,
STATE_STORE_MEM_RIGHT = 5;
reg [3:0] lines_left;
reg [3:0] shift;
reg use_right;
reg [11:0] sprite_addr;
reg [7:0] screen_addr;
reg [15:0] sprite_word;
reg [7:0] screen_byte;
wire [11:0] mem_idx_left = {4'h1, screen_addr};
// Wrap the last 3 bits to wrap a line correctly (a line is 8 bytes)
wire [11:0] mem_idx_right = {4'h1, screen_addr[7:3], screen_addr[2:0] + 1'b1};
reg [3:0] state = STATE_IDLE;
assign busy = state != STATE_IDLE;
// Memory access
always @(*) begin
mem_read = 0;
mem_read_idx = 0;
mem_write = 0;
mem_write_idx = 0;
mem_write_byte = 0;
case (state)
STATE_LOAD_SPRITE: if (!mem_read_ack) begin
mem_read = 1;
mem_read_idx = sprite_addr;
end
STATE_LOAD_MEM_LEFT: if (!mem_read_ack) begin
mem_read = 1;
mem_read_idx = mem_idx_left;
end
STATE_LOAD_MEM_RIGHT: if (!mem_read_ack) begin
mem_read = 1;
mem_read_idx = mem_idx_right;
end
STATE_STORE_MEM_LEFT: begin
mem_write = 1;
mem_write_idx = mem_idx_left;
mem_write_byte = screen_byte;
$display($time, " gpu: [%x] = %b", mem_idx_left, screen_byte);
end
STATE_STORE_MEM_RIGHT:
if (use_right) begin
mem_write = 1;
mem_write_idx = mem_idx_right;
mem_write_byte = screen_byte;
$display($time, " gpu: [%x] = %b", mem_idx_right, screen_byte);
end
endcase
end
always @(posedge clk)
case (state)
STATE_IDLE:
if (draw) begin
$display($time, " gpu: draw %x (%x lines) at (%x, %x)",
addr, lines, x, y);
lines_left <= lines - 1;
sprite_addr <= addr;
screen_addr <= y * WIDTH + x / 8;
shift <= x % 8;
use_right <= (x % 8 != 0);
collision <= 0;
state <= STATE_LOAD_SPRITE;
end
STATE_LOAD_SPRITE:
if (mem_read_ack) begin
sprite_word <= {mem_read_byte, 8'b0} >> shift;
state <= STATE_LOAD_MEM_LEFT;
end
STATE_LOAD_MEM_LEFT:
if (mem_read_ack) begin
screen_byte <= mem_read_byte ^ sprite_word[15:8];
collision <= collision | |(mem_read_byte & sprite_word[15:8]);
state <= STATE_STORE_MEM_LEFT;
end
STATE_STORE_MEM_LEFT:
state <= STATE_LOAD_MEM_RIGHT;
STATE_LOAD_MEM_RIGHT:
if (mem_read_ack) begin
if (use_right) begin
screen_byte <= mem_read_byte ^ sprite_word[7:0];
collision <= collision | |(mem_read_byte & sprite_word[7:0]);
end
state <= STATE_STORE_MEM_RIGHT;
end
STATE_STORE_MEM_RIGHT:
if (lines_left == 0)
state <= STATE_IDLE;
else begin
sprite_addr <= sprite_addr + 1;
screen_addr <= screen_addr + WIDTH;
lines_left <= lines_left - 1;
state <= STATE_LOAD_SPRITE;
end
endcase
endmodule