Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
x393
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
x393
Commits
10e88af6
Commit
10e88af6
authored
Jan 13, 2015
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added modules to byte-serialize write commands and de-serialize them at destinations
parent
56a59c77
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
386 additions
and
1 deletion
+386
-1
cmd_mux.v
cmd_mux.v
+175
-0
ddrc_control.v
memctrl/ddrc_control.v
+1
-1
cmd_deser.v
util_modules/cmd_deser.v
+210
-0
No files found.
cmd_mux.v
0 → 100644
View file @
10e88af6
/*******************************************************************************
* Module: cmd_mux
* Date:2015-01-11
* Author: andrey
* Description: Command multiplexer between AXI and frame-based command sequencer
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* cmd_mux.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* cmd_mux.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale
1
ns
/
1
ps
module
cmd_mux
#(
parameter
AXI_WR_ADDR_BITS
=
13
,
parameter
CONTROL_ADDR
=
'h1000
,
// AXI write address of control write registers
parameter
CONTROL_ADDR_MASK
=
'h1400
,
// AXI write address of control registers
// parameter CONTROL_SS_ADDR= 'h0200, // single-cycle command (2-6 cycles decoded by ROM form some address bits)
// parameter CONTROL_SS_MASK= 'h0200,
parameter
NUM_CYCLES_LOW_BIT
=
6
// decode addresses [NUM_CYCLES_LOW_BIT+:4] into command a/d length
// now all control addresses may generate busy, but only for command sequencer and multy-byte commands
// parameter BUSY_WR_ADDR = 'h1800, // AXI write address to generate busy
// parameter BUSY_WR_ADDR_MASK = 'h1c00 // AXI write address mask to generate busy
)
(
input
clk
,
input
mclk
,
input
rst
,
// direct commands from AXI. No wait but for multi-cycle output and command sequencer (having higher priority)
input
[
AXI_WR_ADDR_BITS
-
1
:
0
]
pre_waddr
,
// AXI write address, before actual writes (to generate busy), valid@start_burst
input
start_wburst
,
// burst start - should generate ~ready (should be AND-ed with !busy internally)
input
[
AXI_WR_ADDR_BITS
-
1
:
0
]
waddr
,
// write address, valid with wr_en
input
wr_en
,
// write enable
input
[
31
:
0
]
wdata
,
// write data, valid with waddr and wr_en
output
busy
,
// interface busy (combinatorial delay from start_wburst and pre_addr), controls AXI FIFO
// frame-based commands from the command sequencer (no wait but for multi-cycle output
input
[
AXI_WR_ADDR_BITS
-
1
:
0
]
cseq_waddr
,
// write address, valid with cseq_wr_en
input
cseq_wr_en
,
// write enable
input
[
31
:
0
]
cseq_wdata
,
// write data, valid with cseq_waddr and cseq_wr_en
output
cseq_ackn
,
// command sequencer address/data accepted
// Write address /data/strobe to slaves. Both parallel and byte-serial data available. COmbined from AXI and command sequencer
output
[
AXI_WR_ADDR_BITS
-
1
:
0
]
par_waddr
,
// parallel address
output
[
31
:
0
]
par_data
,
// parallel 32-bit data
output
[
7
:
0
]
byte_ad
,
// byte-wide address/data (AL-AH-DB0-DB1-DB2-DB3)
output
ad_stb
// low address output strobe (and parallel A/D)
)
;
// Minimal - 1 cycle, AH=DB0=DB1=DB2=DB3=0;
reg
busy_r
=
0
;
reg
selected
=
0
;
// address range to be processed here (outside - buffer(s) and command sequencer?)
wire
fifo_half_empty
;
// just debugging with (* keep = "true" *)
wire
selected_w
;
wire
ss
;
// current command (in par_waddr) is a single-cycle one
reg
[
47
:
0
]
par_ad
;
reg
ad_stb_r
;
// low address output strobe (and parallel A/D)
reg
cmdseq_full_r
;
// address/data from the command sequencer is loaded to internal register (cseq_waddr_r,cseq_wdata_r)
reg
[
AXI_WR_ADDR_BITS
-
1
:
0
]
cseq_waddr_r
;
// registered command address from the sequencer
reg
[
31
:
0
]
cseq_wdata_r
;
// registered command data from the sequencer
reg
[
3
:
0
]
seq_length
;
// encoded ROM output - number of cycles in command sequence, [3] - single cycle
reg
[
4
:
0
]
seq_busy_r
;
// shift register loaded by decoded seq_length
wire
[
3
:
0
]
seq_length_rom_a
;
// address range used to determine command length
wire
can_start_w
;
// can start command cycle (either from sequencer or from AXI)
wire
start_w
;
// start cycle
wire
start_axi_w
;
// start cycle from the AXI (==fifo_re)
wire
fifo_nempty
;
wire
[
AXI_WR_ADDR_BITS
-
1
:
0
]
waddr_fifo_out
;
wire
[
31
:
0
]
wdata_fifo_out
;
assign
selected_w
=
((
pre_waddr
^
CONTROL_ADDR
)
&
CONTROL_ADDR_MASK
)
==
0
;
assign
busy
=
busy_r
&&
(
start_wburst
?
selected_w
:
selected
)
;
// should be just combinatorial delay from start_wburst and decoded command
assign
par_waddr
=
par_ad
[
AXI_WR_ADDR_BITS
-
1
:
0
]
;
// parallel address
assign
par_data
=
par_ad
[
47
:
16
]
;
// parallel 32-bit data
assign
byte_ad
=
par_ad
[
7
:
0
]
;
// byte-wide address/data (AL-AH-DB0-DB1-DB2-DB3)
assign
ad_stb
=
ad_stb_r
;
// low address output strobe (and parallel A/D)
assign
seq_length_rom_a
=
par_ad
[
NUM_CYCLES_LOW_BIT
+:
4
]
;
assign
ss
=
seq_length
[
3
]
;
always
@
(
posedge
clk
or
posedge
rst
)
begin
if
(
rst
)
selected
<=
1'b0
;
else
if
(
start_wburst
)
selected
<=
selected_w
;
if
(
rst
)
busy_r
<=
1'b0
;
else
busy_r
<=
!
fifo_half_empty
;
end
// ROM command length decoder TODO: put actual data
// always @ (seq_length_rom_a) begin
always
@*
case
(
seq_length_rom_a
)
// just temporary - fill out later
4'h00
:
seq_length
<=
9
;
// single-cycle
4'h01
:
seq_length
<=
2
;
// 2-cycle
4'h02
:
seq_length
<=
3
;
4'h03
:
seq_length
<=
4
;
4'h04
:
seq_length
<=
5
;
4'h05
:
seq_length
<=
6
;
// 6-cycle (full)
4'h06
:
seq_length
<=
6
;
4'h07
:
seq_length
<=
6
;
4'h08
:
seq_length
<=
6
;
4'h09
:
seq_length
<=
6
;
4'h0a
:
seq_length
<=
6
;
4'h0b
:
seq_length
<=
6
;
4'h0c
:
seq_length
<=
6
;
4'h0d
:
seq_length
<=
6
;
4'h0e
:
seq_length
<=
6
;
4'h0f
:
seq_length
<=
6
;
endcase
always
@
(
posedge
rst
or
posedge
mclk
)
begin
if
(
rst
)
seq_busy_r
<=
0
;
else
begin
if
(
ad_stb
)
begin
case
(
seq_length
)
4'h2
:
seq_busy_r
<=
5'h01
;
4'h3
:
seq_busy_r
<=
5'h03
;
4'h4
:
seq_busy_r
<=
5'h07
;
4'h5
:
seq_busy_r
<=
5'h0f
;
4'h6
:
seq_busy_r
<=
5'h1f
;
default:
seq_busy_r
<=
5'h00
;
endcase
end
else
seq_busy_r
<=
{
1'b0
,
seq_busy_r
[
3
:
0
]
};
end
end
assign
can_start_w
=
ad_stb_r
?
ss
:
!
seq_busy_r
[
1
]
;
assign
start_axi_w
=
can_start_w
&&
~
cmdseq_full_r
&&
fifo_nempty
;
assign
start_w
=
can_start_w
&&
(
cmdseq_full_r
||
fifo_nempty
)
;
always
@
(
posedge
rst
or
posedge
mclk
)
begin
if
(
rst
)
ad_stb_r
<=
0
;
else
ad_stb_r
<=
start_w
;
end
always
@
(
posedge
mclk
)
begin
if
(
start_w
)
par_ad
<={
cmdseq_full_r
?
cseq_wdata_r
:
wdata_fifo_out
,{
(
16
-
AXI_WR_ADDR_BITS
)
{
1'b0
}},
cmdseq_full_r
?
cseq_waddr_r
:
waddr_fifo_out
};
else
par_ad
<={
8'b0
,
par_ad
[
39
:
0
]
};
end
assign
cseq_ackn
=
cseq_wr_en
&&
(
!
cmdseq_full_r
||
can_start_w
)
;
// cmddseq_full has priority over axi, so (can_start_w && cmdseq_full_r)
always
@
(
posedge
rst
or
posedge
mclk
)
begin
if
(
rst
)
cmdseq_full_r
<=
0
;
else
cmdseq_full_r
<=
cseq_ackn
||
(
cmdseq_full_r
&&
!
can_start_w
)
;
end
always
@
(
posedge
mclk
)
begin
if
(
cseq_ackn
)
begin
cseq_waddr_r
<=
cseq_waddr
;
cseq_wdata_r
<=
cseq_wdata
;
end
end
/* FIFO to cross clock boundary */
fifo_cross_clocks
#(
.
DATA_WIDTH
(
AXI_WR_ADDR_BITS
+
32
)
,
.
DATA_DEPTH
(
4
)
)
fifo_cross_clocks_i
(
.
rst
(
rst
)
,
// input
.
rclk
(
mclk
)
,
// input
.
wclk
(
clk
)
,
// input
.
we
(
wr_en
&&
selected
)
,
// input
.
re
(
start_axi_w
)
,
// input
.
data_in
(
{
waddr
[
AXI_WR_ADDR_BITS
-
1
:
0
]
,
wdata
[
31
:
0
]
}
)
,
// input[15:0]
.
data_out
(
{
waddr_fifo_out
[
AXI_WR_ADDR_BITS
-
1
:
0
]
,
wdata_fifo_out
[
31
:
0
]
}
)
,
// output[15:0]
.
nempty
(
fifo_nempty
)
,
// output
.
half_empty
(
fifo_half_empty
)
// output
)
;
endmodule
memctrl/ddrc_control.v
View file @
10e88af6
...
...
@@ -177,7 +177,7 @@ module ddrc_control #(
reg
busy_r
=
0
;
reg
selected
=
0
;
reg
selected_busy
=
0
;
reg
selected_busy
=
0
;
// decoded from address, if false - busy_r is ignored (always ready)
wire
fifo_half_empty
;
// just debugging with (* keep = "true" *)
wire
[
AXI_WR_ADDR_BITS
-
1
:
0
]
waddr_fifo_out
;
...
...
util_modules/cmd_deser.v
0 → 100644
View file @
10e88af6
/*******************************************************************************
* Module: cmd_deser
* Date:2015-01-12
* Author: andrey
* Description: Expand command address/data from a byte-wide
*
* Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
* cmd_deser.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* cmd_deser.v is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale
1
ns
/
1
ps
module
cmd_deser
#(
parameter
ADDR
=
0
,
parameter
ADDR_MASK
=
'hffff
,
parameter
NUM_CYCLES
=
6
,
parameter
ADDR_WIDTH
=
16
,
parameter
DATA_WIDTH
=
32
)(
input
rst
,
input
clk
,
input
[
7
:
0
]
ad
,
input
stb
,
output
[
ADDR_WIDTH
-
1
:
0
]
addr
,
output
[
DATA_WIDTH
-
1
:
0
]
data
,
output
we
)
;
generate
if
(
NUM_CYCLES
==
1
)
cmd_deser_single
#
(
.
ADDR
(
ADDR
)
,
.
ADDR_MASK
(
ADDR_MASK
)
,
.
ADDR_WIDTH
(
ADDR_WIDTH
)
,
.
DATA_WIDTH
(
DATA_WIDTH
)
)
i_cmd_deser_single
(
.
rst
(
rst
)
,
.
clk
(
clk
)
,
.
ad
(
ad
)
,
.
stb
(
stb
)
,
.
addr
(
addr
)
,
.
data
(
data
)
,
.
we
(
we
)
)
;
else
if
(
NUM_CYCLES
==
2
)
cmd_deser_dual
#
(
.
ADDR
(
ADDR
)
,
.
ADDR_MASK
(
ADDR_MASK
)
,
.
ADDR_WIDTH
(
ADDR_WIDTH
)
,
.
DATA_WIDTH
(
DATA_WIDTH
)
)
i_cmd_deser_single
(
.
rst
(
rst
)
,
.
clk
(
clk
)
,
.
ad
(
ad
)
,
.
stb
(
stb
)
,
.
addr
(
addr
)
,
.
data
(
data
)
,
.
we
(
we
)
)
;
else
cmd_deser_multi
#
(
.
ADDR
(
ADDR
)
,
.
ADDR_MASK
(
ADDR_MASK
)
,
.
NUM_CYCLES
(
NUM_CYCLES
)
,
.
ADDR_WIDTH
(
ADDR_WIDTH
)
,
.
DATA_WIDTH
(
DATA_WIDTH
)
)
i_cmd_deser_single
(
.
rst
(
rst
)
,
.
clk
(
clk
)
,
.
ad
(
ad
)
,
.
stb
(
stb
)
,
.
addr
(
addr
)
,
.
data
(
data
)
,
.
we
(
we
)
)
;
endgenerate
endmodule
module
cmd_deser_single
#(
parameter
ADDR
=
0
,
parameter
ADDR_MASK
=
'hffff
,
parameter
ADDR_WIDTH
=
8
,
// <=8
parameter
DATA_WIDTH
=
1
// will 0 work?
)(
input
rst
,
input
clk
,
input
[
7
:
0
]
ad
,
input
stb
,
output
[
ADDR_WIDTH
-
1
:
0
]
addr
,
output
[
DATA_WIDTH
-
1
:
0
]
data
,
output
we
)
;
localparam
ADDR_LOW
=
ADDR
&
8'hff
;
// localparam ADDR_HIGH=(ADDR>>8) & 8'hff;
localparam
ADDR_MASK_LOW
=
ADDR_MASK
&
8'hff
;
// localparam ADDR_MASK_HIGH=(ADDR_MASK>>8) & 8'hff;
reg
[
7
:
0
]
deser_r
;
// reg stb_d;
wire
match_low
;
reg
we_r
;
assign
we
=
we_r
;
assign
match_low
=
((
ad
^
ADDR_LOW
)
&
(
8'hff
&
ADDR_MASK_LOW
))
==
0
;
always
@
(
posedge
rst
or
posedge
clk
)
begin
if
(
rst
)
we_r
<=
0
;
else
we_r
<=
match_low
&&
stb
;
if
(
rst
)
deser_r
<=
0
;
else
if
(
match_low
&&
stb
)
deser_r
<=
ad
;
end
always
@
(
posedge
clk
)
begin
if
(
match_low
&&
stb
)
deser_r
<=
ad
;
end
assign
data
={
DATA_WIDTH
{
1'b0
}};
assign
addr
=
deser_r
[
ADDR_WIDTH
-
1
:
0
]
;
endmodule
module
cmd_deser_dual
#(
parameter
ADDR
=
0
,
parameter
ADDR_MASK
=
'hffff
,
parameter
ADDR_WIDTH
=
12
,
// <=16
parameter
DATA_WIDTH
=
1
// will 0 work?
)(
input
rst
,
input
clk
,
input
[
7
:
0
]
ad
,
input
stb
,
output
[
ADDR_WIDTH
-
1
:
0
]
addr
,
output
[
DATA_WIDTH
-
1
:
0
]
data
,
output
we
)
;
localparam
ADDR_LOW
=
ADDR
&
8'hff
;
localparam
ADDR_HIGH
=
(
ADDR
>>
8
)
&
8'hff
;
localparam
ADDR_MASK_LOW
=
ADDR_MASK
&
8'hff
;
localparam
ADDR_MASK_HIGH
=
(
ADDR_MASK
>>
8
)
&
8'hff
;
reg
[
15
:
0
]
deser_r
;
reg
stb_d
;
wire
match_low
;
wire
match_high
;
reg
we_r
;
assign
we
=
we_r
;
assign
match_low
=
((
ad
^
ADDR_LOW
)
&
(
8'hff
&
ADDR_MASK_LOW
))
==
0
;
assign
match_high
=
((
ad
^
ADDR_HIGH
)
&
(
8'hff
&
ADDR_MASK_HIGH
))
==
0
;
always
@
(
posedge
rst
or
posedge
clk
)
begin
if
(
rst
)
stb_d
<=
1'b0
;
else
stb_d
<=
match_low
&&
stb
;
if
(
rst
)
we_r
<=
1'b0
;
else
we_r
<=
match_high
&&
stb_d
;
end
always
@
(
posedge
clk
)
begin
if
((
match_low
&&
stb
)
||
(
match_high
&&
stb_d
))
deser_r
[
15
:
0
]
<=
{
ad
,
deser_r
[
15
:
8
]
};
end
assign
data
={
DATA_WIDTH
{
1'b0
}};
assign
addr
=
deser_r
[
ADDR_WIDTH
-
1
:
0
]
;
endmodule
module
cmd_deser_multi
#(
parameter
ADDR
=
0
,
parameter
ADDR_MASK
=
'hffff
,
parameter
NUM_CYCLES
=
6
,
// >=3
parameter
ADDR_WIDTH
=
16
,
parameter
DATA_WIDTH
=
32
)(
input
rst
,
input
clk
,
input
[
7
:
0
]
ad
,
input
stb
,
output
[
ADDR_WIDTH
-
1
:
0
]
addr
,
output
[
DATA_WIDTH
-
1
:
0
]
data
,
output
we
)
;
localparam
ADDR_LOW
=
ADDR
&
8'hff
;
localparam
ADDR_HIGH
=
(
ADDR
>>
8
)
&
8'hff
;
localparam
ADDR_MASK_LOW
=
ADDR_MASK
&
8'hff
;
localparam
ADDR_MASK_HIGH
=
(
ADDR_MASK
>>
8
)
&
8'hff
;
reg
[
8
*
NUM_CYCLES
-
1
:
0
]
deser_r
;
reg
stb_d
;
wire
match_low
;
wire
match_high
;
reg
[
NUM_CYCLES
-
2
:
0
]
sr
;
assign
we
=
sr
[
0
]
;
// we_r;
assign
match_low
=
((
ad
^
ADDR_LOW
)
&
(
8'hff
&
ADDR_MASK_LOW
))
==
0
;
assign
match_high
=
((
ad
^
ADDR_HIGH
)
&
(
8'hff
&
ADDR_MASK_HIGH
))
==
0
;
always
@
(
posedge
rst
or
posedge
clk
)
begin
if
(
rst
)
stb_d
<=
1'b0
;
else
stb_d
<=
match_low
&&
stb
;
if
(
rst
)
sr
<=
0
;
else
if
(
match_high
&&
stb_d
)
sr
<=
{
NUM_CYCLES
-
1
{
1'b1
}};
else
sr
<=
{
1'b0
,
sr
[
NUM_CYCLES
-
3
:
0
]
};
end
always
@
(
posedge
clk
)
begin
if
((
match_low
&&
stb
)
||
(
match_high
&&
stb_d
)
||
(
|
sr
))
deser_r
[
8
*
NUM_CYCLES
-
1
:
0
]
<=
{
ad
,
deser_r
[
8
*
NUM_CYCLES
-
1
:
8
]
};
end
assign
data
=
deser_r
[
DATA_WIDTH
+
15
:
16
]
;
assign
addr
=
deser_r
[
ADDR_WIDTH
-
1
:
0
]
;
endmodule
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment