Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Koen Martens
gmcpu8
Commits
03b4f683
Commit
03b4f683
authored
Aug 16, 2019
by
Koen Martens
Browse files
uart: refactor top-level control to use transmit module
parent
41d41a01
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/verilog/wishbone/uart/uart.v
View file @
03b4f683
`include
"transmit.v"
module
uart
#(
parameter
DATA_WIDTH
=
8
,
parameter
ADDR_WIDTH
=
3
,
parameter
CLK_RATE
=
16000000
parameter
ADDR_WIDTH
=
3
)(
input
wire
sin
,
output
reg
sout
,
...
...
@@ -27,69 +28,70 @@ module uart #(
reg
[
7
:
0
]
LCR
;
/* Line Control Register */
wire
LCR_DLAB
=
LCR
[
7
];
/* Divisor Latch Access Bit */
reg
[
7
:
0
]
LSR
;
/* Line Status Register */
localparam
LSR_BIT_THRE
=
5
;
localparam
LSR_BIT_TEMT
=
6
;
//
reg
[
15
:
0
]
clk16_counter
;
reg
reset_clk16_counter
;
reg
[
3
:
0
]
clk_counter
;
reg
[
7
:
0
]
TSR
;
/* Transmitter Shift Register */
reg
[
3
:
0
]
transmit_bit_count
;
always
@
(
posedge
clk_i
)
begin
if
(
rst_i
||
reset_clk16_counter
||
(
clk16_counter
==
0
))
begin
clk16_counter
<=
(
{
DLM
,
DLL
}
)
-
1
;
reset_clk16_counter
<=
1'b0
;
clk_counter
<=
clk_counter
+
1
;
end
else
begin
clk16_counter
<=
clk16_counter
-
1
;
end
end
wire
transmit_clk
=
(
clk_counter
==
0
)
?
1'b1
:
1'b0
;
/* Line Status Register */
wire
[
7
:
0
]
LSR
=
{
LSR_FIFO_ERROR
,
LSR_TEMT
,
LSR_THRE
,
LSR_BI
,
LSR_FE
,
LSR_PE
,
LSR_OE
,
LSR_DR
}
;
reg
LSR_DR
;
reg
LSR_OE
;
reg
LSR_PE
;
reg
LSR_FE
;
reg
LSR_BI
;
reg
LSR_THRE
;
wire
LSR_TEMT
=
LSR_THRE
&
tsr_empty
;
reg
LSR_FIFO_ERROR
;
// transmitter
wire
tsr_latched
;
wire
tsr_empty
;
transmit
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
DIVISOR_WIDTH
(
16
)
)
transmitter
(
.
clk_i
(
clk_i
),
.
rst_i
(
rst_i
),
.
data_i
(
THR
),
.
clk_divisor_i
(
{
DLM
,
DLL
}
),
.
sout
(
sout
),
.
data_latched_o
(
tsr_latched
),
.
empty_o
(
tsr_empty
),
.
data_ready_i
(
~
LSR_THRE
)
);
always
@
(
posedge
clk_i
)
begin
if
(
rst_i
)
begin
RBR
<=
'b0
;
THR
<=
'b0
;
DLL
<=
'b0
;
DLM
<=
'b0
;
TSR
<=
1'b0
;
THR
<=
'b0
;
LCR
<=
'b0
;
LSR
<=
'b0
|
(
1
<<
LSR_BIT_THRE
)
|
(
1
<<
LSR_BIT_TEMT
);
clk16_counter
=
0
;
clk_counter
=
0
;
reset_clk16_counter
=
1'b1
;
sout
<=
1'b1
;
transmit_bit_count
<=
1'b0
;
transmit_state
<=
TRANSMIT_IDLE
;
RBR
<=
'b0
;
THR
<=
'b0
;
DLL
<=
'b0
;
DLM
<=
'b0
;
THR
<=
'b0
;
LCR
<=
'b0
;
LSR_OE
=
1'b0
;
LSR_PE
=
1'b0
;
LSR_FE
=
1'b0
;
LSR_BI
=
1'b0
;
LSR_THRE
=
1'b1
;
LSR_FIFO_ERROR
=
1'b0
;
LSR_DR
=
1'b0
;
dat_o
=
{
DATA_WIDTH
{
1'b0
}}
;
ack_o
=
1'b0
;
end
else
begin
if
(
tsr_latched
)
LSR_THRE
=
1'b1
;
if
(
cyc_i
&
stb_i
&
~
ack_o
)
begin
if
(
we_i
)
begin
case
(
adr_i
)
3'b000
:
// RBR / DLL
if
(
LCR_DLAB
)
begin
DLL
=
dat_i
;
reset_clk16_counter
=
1'b1
;
end
3'b001
:
// THR / DLM
if
(
LCR_DLAB
)
begin
DLM
=
dat_i
;
reset_clk16_counter
=
1'b1
;
end
else
begin
THR
=
dat_i
;
LSR
[
LSR_BIT
_THRE
]
=
1'b0
;
LSR_THRE
=
1'b0
;
end
3'b011
:
// LCR
LCR
=
dat_i
;
endcase
end
case
(
adr_i
)
3'b000
:
dat_o
=
LCR_DLAB
?
DLL
:
RBR
;
3'b011
:
dat_o
=
LCR
;
3'b101
:
begin
dat_o
=
LSR
;
LSR
=
LSR
&
~
(
8'b00011110
)
;
LSR
_OE
=
1'b0
;
LSR_PE
=
1'b0
;
LSR_FE
=
1'b0
;
LSR_BI
=
1'b0
;
end
default:
dat_o
=
'b0
;
endcase
...
...
@@ -101,49 +103,4 @@ module uart #(
end
end
// transmit
reg
[
2
:
0
]
transmit_state
;
localparam
TRANSMIT_IDLE
=
3'b001
;
localparam
TRANSMIT_SHIFT
=
3'b010
;
localparam
TRANSMIT_STOP
=
3'b100
;
always
@
(
posedge
transmit_clk
)
begin
case
(
transmit_state
)
TRANSMIT_IDLE
:
begin
sout
=
1'b1
;
if
(
LSR
[
LSR_BIT_THRE
]
==
1'b0
)
begin
sout
=
1'b0
;
// start bit
TSR
=
THR
;
LSR
[
LSR_BIT_THRE
]
=
1'b1
;
transmit_bit_count
=
7
;
transmit_state
=
TRANSMIT_SHIFT
;
end
else
begin
transmit_state
=
TRANSMIT_IDLE
;
end
end
TRANSMIT_SHIFT
:
begin
if
(
transmit_bit_count
==
0
)
begin
transmit_state
=
TRANSMIT_STOP
;
end
sout
=
TSR
[
0
];
TSR
=
TSR
>>
1
;
transmit_state
=
(
transmit_bit_count
==
0
)
?
TRANSMIT_STOP
:
TRANSMIT_SHIFT
;
transmit_bit_count
=
transmit_bit_count
-
1
;
end
TRANSMIT_STOP
:
begin
sout
=
1'b1
;
transmit_state
=
TRANSMIT_IDLE
;
end
default
:
begin
sout
=
1'b1
;
transmit_state
=
TRANSMIT_IDLE
;
end
endcase
end
endmodule
src/verilog/wishbone/uart/uart_tb.v
View file @
03b4f683
...
...
@@ -68,6 +68,35 @@ module uart_tb();
`include
"common/testbench_tasks/wb_check_read.v"
`include
"common/testbench_tasks/wb_write.v"
task
verify_sout
(
input
[
TB_DATA_WIDTH
-
1
:
0
]
expected
,
input
string
message
=
""
,
input
integer
start_skip
=
0
,
input
integer
stop_skip
=
0
);
integer
bit_index
;
string
formatted
;
begin
repeat
((
TB_DIVIDER
*
16
)
-
start_skip
)
begin
@
(
posedge
clk
);
tb_assert
(
tb_sout
===
1'b0
,
{
message
,
", start bit = space (0)"
}
);
end
bit_index
=
0
;
repeat
(
8
)
begin
repeat
(
TB_DIVIDER
*
16
)
begin
@
(
posedge
clk
);
$
sformat
(
formatted
,
{
message
,
", bit %0d (%b)"
}
,
bit_index
,
expected
[
bit_index
]);
tb_assert
(
tb_sout
===
expected
[
bit_index
],
formatted
);
end
bit_index
+=
1
;
end
repeat
((
TB_DIVIDER
*
16
)
-
stop_skip
)
begin
@
(
posedge
clk
);
tb_assert
(
tb_sout
===
1'b1
,
{
message
,
", stop bit = mark (1)"
}
);
end
end
endtask
reg
[
TB_DATA_WIDTH
-
1
:
0
]
read_data
;
integer
retry_count
;
...
...
@@ -106,38 +135,44 @@ module uart_tb();
wb_write
(
1
,
8'h4b
);
wb_read
(
5
,
read_data
);
tb_assert
(
!
(
read_data
&
(
1
<<
UUT
.
LSR_BIT_THRE
)),
"THRE not asserted"
);
tb_assert
(
read_data
[
5
]
===
1'b1
,
"THRE asserted"
);
tb_assert
(
read_data
[
6
]
===
1'b0
,
"TEMT deasserted"
);
// wait for THRE
retry_count
=
0
;
while
(
!
(
read_data
&
(
1
<<
UUT
.
LSR_BIT_THRE
)))
begin
while
(
!
(
read_data
&
(
1
<<
5
)))
begin
wb_read
(
5
,
read_data
);
retry_count
+=
1
;
tb_assert
(
retry_count
<
100
,
"wait for THRE timeout"
);
end
tb_assert
(
tb_sout
==
1'b0
,
"start bit = space (0)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b1
,
"bit0 = mark (1)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b1
,
"bit0 = mark (1)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b0
,
"bit0 = space (0)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b1
,
"bit0 = mark (1)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b0
,
"bit0 = space (0)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b0
,
"bit0 = space (0)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b1
,
"bit0 = mark (1)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b0
,
"bit0 = space (0)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
tb_assert
(
tb_sout
==
1'b1
,
"stop bit = mark (1)"
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
repeat
(
TB_DIVIDER
*
16
)
@
(
posedge
clk
);
// write 8'b10110001 to THR (reg 1)
wb_write
(
1
,
8'b10110001
);
wb_read
(
5
,
read_data
);
tb_assert
(
read_data
[
5
]
===
1'b0
,
"THRE de-asserted after write byte 2"
);
tb_assert
(
read_data
[
6
]
===
1'b0
,
"TEMT deasserted after write byte 2"
);
verify_sout
(
8'h4b
,
"byte 1"
,
12
,
16
);
wb_read
(
5
,
read_data
);
tb_assert
(
read_data
[
5
]
===
1'b0
,
"THRE deasserted at end of byte 1"
);
tb_assert
(
read_data
[
6
]
===
1'b0
,
"TEMT deasserted at end of byte 1"
);
repeat
(
12
)
@
(
posedge
clk
);
wb_read
(
5
,
read_data
);
tb_assert
(
read_data
[
5
]
===
1'b1
,
"THRE asserted at start of byte 2"
);
tb_assert
(
read_data
[
6
]
===
1'b0
,
"TEMT deasserted at start of byte 2"
);
verify_sout
(
8'b10110001
,
"byte 2"
,
4
,
0
);
repeat
(
TB_DIVIDER
*
16
)
begin
@
(
posedge
clk
);
wb_read
(
5
,
read_data
);
tb_assert
(
read_data
[
5
]
===
1'b1
,
"THRE asserted after byte 2"
);
tb_assert
(
read_data
[
6
]
===
1'b1
,
"TEMT asserted after byte 2"
);
tb_assert
(
tb_sout
===
1'b1
,
"sout 1 when idling"
);
end
$
display
(
"passed"
);
$
finish
;
...
...
Write
Preview
Supports
Markdown
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