forked from embmicro/mojo-base-project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathavr_interface.v
148 lines (129 loc) · 3.45 KB
/
avr_interface.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
module avr_interface #(
parameter CLK_RATE = 50000000
)(
input clk,
input rst,
// cclk, or configuration clock is used when the FPGA is begin configured.
// The AVR will hold cclk high when it has finished initializing.
// It is important not to drive the lines connecting to the AVR
// until cclk is high for a short period of time to avoid contention.
input cclk,
// signal the rest of the chip we are ready
output ready,
// AVR SPI Signals
output spi_miso,
input spi_mosi,
input spi_sck,
input spi_ss,
// Register interface signals
output [5:0] reg_addr,
output write,
output new_req,
output [7:0] write_value,
input [7:0] read_value
);
wire n_rdy = !ready;
wire spi_done;
wire [7:0] spi_dout;
wire frame_start, frame_end;
wire tx_m;
wire spi_miso_m;
localparam STATE_SIZE = 2;
localparam IDLE = 0,
ADDR = 1,
WRITE = 2,
READ = 3;
reg [STATE_SIZE-1:0] state_d, state_q;
reg [7:0] write_value_d, write_value_q;
reg write_d, write_q;
reg auto_inc_d, auto_inc_q;
reg [5:0] reg_addr_d, reg_addr_q;
reg new_req_d, new_req_q;
reg first_write_d, first_write_q;
assign reg_addr = reg_addr_q;
assign write = write_q;
assign new_req = new_req_q;
assign write_value = write_value_q;
// this signal connects to the AVR and should be Z when the AVR isn't ready
assign spi_miso = ready && !spi_ss ? spi_miso_m : 1'bZ;
// cclk_detector is used to detect when cclk is high signaling when
// the AVR is ready
cclk_detector #(.CLK_RATE(CLK_RATE)) cclk_detector (
.clk(clk),
.rst(rst),
.cclk(cclk),
.ready(ready)
);
spi_slave spi_slave (
.clk(clk),
.rst(n_rdy),
.ss(spi_ss),
.mosi(spi_mosi),
.miso(spi_miso_m),
.sck(spi_sck),
.done(spi_done),
.din(read_value),
.dout(spi_dout),
.frame_start(frame_start),
.frame_end(frame_end)
);
always @(*) begin
write_value_d = write_value_q;
write_d = write_q;
auto_inc_d = auto_inc_q;
reg_addr_d = reg_addr_q;
new_req_d = 1'b0;
state_d = state_q;
first_write_d = first_write_q;
case (state_q)
IDLE: begin
if (frame_start)
state_d = ADDR;
end
ADDR: begin
if (spi_done) begin
first_write_d = 1'b1;
{write_d, auto_inc_d, reg_addr_d} = spi_dout;
if (spi_dout[7]) begin
state_d = WRITE;
end else begin
state_d = READ;
new_req_d = 1'b1;
end
end
end
WRITE: begin
if (spi_done) begin
first_write_d = 1'b0;
if (auto_inc_q && !first_write_q)
reg_addr_d = reg_addr_q + 1'b1;
new_req_d = 1'b1;
write_value_d = spi_dout;
end
end
READ: begin
if (spi_done) begin
if (auto_inc_q)
reg_addr_d = reg_addr_q + 1'b1;
new_req_d = 1'b1;
end
end
default: state_d = IDLE;
endcase
if (frame_end)
state_d = IDLE;
end
always @(posedge clk) begin
if (n_rdy) begin
state_q <= IDLE;
end else begin
state_q <= state_d;
end
write_value_q <= write_value_d;
write_q <= write_d;
auto_inc_q <= auto_inc_d;
reg_addr_q <= reg_addr_d;
new_req_q <= new_req_d;
first_write_q <= first_write_d;
end
endmodule