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
|
// Copyright 2015, Brian Swetland <swetland@frotz.net>
// Licensed under the Apache License, Version 2.0.
`timescale 1ns / 1ps
module spi_debug_ifc(
input spi_clk,
input spi_cs_i,
input spi_data_i,
output spi_data_o,
input sys_clk,
output sys_wr_o,
output [15:0]sys_waddr_o,
output [15:0]sys_wdata_o
);
reg [15:0]spi_shift = 16'd0;
reg [16:0]spi_data = 17'd0;
reg [3:0]spi_count = 4'd0;
reg spi_signal = 1'd0;
reg spi_flag = 1'd0;
assign spi_data_o = 1'b0;
wire [15:0]spi_next = { spi_data_i, spi_shift[15:1] };
reg [15:0]spi_shift_next;
reg [16:0]spi_data_next;
reg [3:0]spi_count_next;
reg spi_signal_next;
reg spi_flag_next;
always @(*) begin
spi_shift_next = spi_shift;
spi_data_next = spi_data;
spi_count_next = spi_count;
spi_signal_next = spi_signal;
spi_flag_next = spi_flag;
if (spi_cs_i) begin
spi_count_next = 4'd0;
spi_flag_next = 1'b1;
end else begin
spi_shift_next = spi_next;
spi_count_next = spi_count + 4'd1;
if (spi_count == 4'd15) begin
spi_data_next = { spi_flag, spi_next };
spi_signal_next = ~spi_signal;
spi_flag_next = 1'b0;
end
end
end
always @(posedge spi_clk) begin
spi_shift <= spi_shift_next;
spi_data <= spi_data_next;
spi_count <= spi_count_next;
spi_signal <= spi_signal_next;
spi_flag <= spi_flag_next;
end
wire sys_signal;
sync_oneway sync_spi_sys(
.txclk(spi_clk),
.txdat(spi_signal),
.rxclk(sys_clk),
.rxdat(sys_signal)
);
reg sys_signal_ack = 1'b0;
reg enabled = 1'b0;
reg [15:0]addr;
reg [15:0]data;
reg wr = 1'b0;
reg [15:0]addr_next;
reg [15:0]data_next;
reg enabled_next;
reg sys_signal_ack_next;
reg wr_next;
reg [15:0]delay = 16'd0;
reg [15:0]delay_next;
always @(*) begin
delay_next = delay;
addr_next = addr;
data_next = data;
sys_signal_ack_next = sys_signal_ack;
wr_next = wr;
// ensure we're up and running before accepting writes
// there's got to be a nicer way to do this
if (delay != 16'hFFFF) begin
delay_next = delay + 1'd1;
enabled_next = 1'b0;
end else begin
enabled_next = 1'b1;
end
if (sys_signal ^ sys_signal_ack) begin
sys_signal_ack_next = ~sys_signal_ack;
if (spi_data[16]) begin
addr_next = spi_data[15:0];
end else begin
data_next = spi_data[15:0];
wr_next = 1'b1;
end
end else begin
if (wr) begin
wr_next = 1'b0;
addr_next = addr + 16'd1;
end
end
end
always @(posedge sys_clk) begin
delay <= delay_next;
addr <= addr_next;
data <= data_next;
enabled <= enabled_next;
sys_signal_ack <= sys_signal_ack_next;
wr <= wr_next;
end
assign sys_wr_o = wr & enabled;
assign sys_waddr_o = addr;
assign sys_wdata_o = data;
endmodule
module sync_oneway(
input txclk,
input txdat,
input rxclk,
output rxdat
);
reg a = 0;
// these should be adjacent
reg b = 0, c = 0;
always @(posedge txclk)
a <= txdat;
always @(posedge rxclk) begin
b <= a;
c <= b;
end
assign rxdat = c;
endmodule
|