Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
R
risc-v-qemu
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Projekt Telematik SS23 QEMU
risc-v-qemu
Commits
31c5762c
Commit
31c5762c
authored
Jun 27, 2023
by
davip00
Browse files
Options
Downloads
Patches
Plain Diff
Flesh out ESP32-C3 UART FIFO implementation
parent
3dc0ad24
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
hw/char/esp32_c3_uart.c
+142
-51
142 additions, 51 deletions
hw/char/esp32_c3_uart.c
hw/char/trace-events
+7
-0
7 additions, 0 deletions
hw/char/trace-events
include/hw/char/esp32_c3_uart.h
+12
-4
12 additions, 4 deletions
include/hw/char/esp32_c3_uart.h
with
161 additions
and
55 deletions
hw/char/esp32_c3_uart.c
+
142
−
51
View file @
31c5762c
...
@@ -24,68 +24,158 @@
...
@@ -24,68 +24,158 @@
#include
"hw/qdev-properties-system.h"
#include
"hw/qdev-properties-system.h"
#include
"migration/vmstate.h"
#include
"migration/vmstate.h"
#include
"trace.h"
#include
"trace.h"
#include
"trace/trace-hw_char.h"
static
void
uart_rx_fifo_push
(
ESP32C3UARTState
*
s
,
uint8_t
byte
)
{
s
->
rx_fifo
[
s
->
rx_fifo_head
]
=
byte
;
s
->
rx_fifo_head
++
;
if
(
s
->
rx_fifo_head
>=
ESP32_C3_UART_FIFO_LENGTH
)
{
s
->
rx_fifo_head
=
0
;
}
/* Increment number of bytes in RX FIFO tracked by control register */
uint32_t
bytes
=
s
->
regs
[
R_UART_STATUS
]
&
R_UART_STATUS_UART_RXFIFO_CNT_MASK
;
bytes
+=
1
;
s
->
regs
[
R_UART_STATUS
]
|=
bytes
;
}
static
void
uart_tx_fifo_push
(
ESP32C3UARTState
*
s
,
uint8_t
byte
)
{
s
->
tx_fifo
[
s
->
tx_fifo_head
]
=
byte
;
s
->
tx_fifo_head
++
;
if
(
s
->
tx_fifo_head
>=
ESP32_C3_UART_FIFO_LENGTH
)
{
s
->
tx_fifo_head
=
0
;
}
/* Increment number of bytes in TX FIFO tracked by control register */
uint32_t
bytes
=
s
->
regs
[
R_UART_STATUS
]
&
R_UART_STATUS_UART_TXFIFO_CNT_MASK
;
bytes
+=
1
;
s
->
regs
[
R_UART_STATUS
]
|=
bytes
;
}
static
bool
uart_rx_fifo_pull
(
ESP32C3UARTState
*
s
,
uint8_t
*
out
)
{
if
(
s
->
rx_fifo_tail
>
s
->
rx_fifo_head
)
{
trace_esp32_c3_uart_rx_fifo_underrun
();
return
FALSE
;
}
*
out
=
s
->
rx_fifo
[
s
->
rx_fifo_tail
];
s
->
rx_fifo_tail
++
;
if
(
s
->
rx_fifo_tail
>=
ESP32_C3_UART_FIFO_LENGTH
)
{
s
->
rx_fifo_tail
=
0
;
}
/* Decrement number of bytes in RX FIFO tracked by control register */
uint32_t
bytes
=
s
->
regs
[
R_UART_STATUS
]
&
R_UART_STATUS_UART_RXFIFO_CNT_MASK
;
bytes
-=
1
;
s
->
regs
[
R_UART_STATUS
]
|=
bytes
;
return
TRUE
;
}
static
bool
uart_tx_fifo_pull
(
ESP32C3UARTState
*
s
,
uint8_t
*
out
)
{
if
(
s
->
tx_fifo_tail
>
s
->
tx_fifo_head
)
{
trace_esp32_c3_uart_tx_fifo_underrun
();
return
FALSE
;
}
*
out
=
s
->
tx_fifo
[
s
->
tx_fifo_tail
];
s
->
tx_fifo_tail
++
;
if
(
s
->
tx_fifo_tail
>=
ESP32_C3_UART_FIFO_LENGTH
)
{
s
->
tx_fifo_tail
=
0
;
}
/* Decrement number of bytes in TX FIFO tracked by control register */
uint32_t
bytes
=
s
->
regs
[
R_UART_STATUS
]
&
R_UART_STATUS_UART_TXFIFO_CNT_MASK
;
bytes
-=
1
;
s
->
regs
[
R_UART_STATUS
]
|=
bytes
;
return
TRUE
;
}
static
uint64_t
uart_read
(
void
*
opaque
,
hwaddr
addr
,
unsigned
int
size
)
static
uint64_t
uart_read
(
void
*
opaque
,
hwaddr
addr
,
unsigned
int
size
)
{
{
/* Note that this is for reading I/O memory, not FIFO */
/* Note that this is for reading I/O memory, not FIFO memory */
/*
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
uint64_t
r
;
uint64_t
r
;
TODO: Check if enabled
uint8_t
byte
;
if (!s->rx_enabled) {
return 0;
}
switch
(
addr
)
{
switch
(
addr
)
{
case
A_UART_FIFO
:
if
(
!
uart_rx_fifo_pull
(
s
,
&
byte
))
{
r
=
0
;
}
else
{
r
=
byte
;
}
break
;
default:
default:
r
=
s
->
regs
[
addr
/
4
];
r
=
s
->
regs
[
addr
/
4
];
break
;
break
;
}
}
trace_esp32_c3_uart_read(addr, r, size);
trace_esp32_c3_uart_read
(
addr
,
r
,
size
);
return
r
;
return
r
;
*/
return
0
;
}
}
static
gboolean
uart_transmit
(
void
*
do_not_use
,
GIOCondition
cond
,
void
*
opaque
)
static
gboolean
uart_transmit
(
void
*
do_not_use
,
GIOCondition
cond
,
void
*
opaque
)
{
{
/*
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
int
r
;
int
r
;
if (s->tx_fifo_pos == 0) {
if
(
s
->
tx_fifo_head
==
0
)
{
/* Don't have any data */
return
FALSE
;
return
FALSE
;
}
}
*/
/* TODO: Bounds check / wraparound */
/* TODO: Bounds check / wraparound */
/*
uint8_t
c
;
uint8_t c = s->tx_fifo[s->tx_fifo_pos];
if
(
!
uart_tx_fifo_pull
(
s
,
&
c
))
{
s->tx_fifo_pos++;
/* FIFO underrun */
return
FALSE
;
}
r
=
qemu_chr_fe_write
(
&
s
->
chr
,
&
c
,
1
);
r
=
qemu_chr_fe_write
(
&
s
->
chr
,
&
c
,
1
);
return
TRUE
;
return
TRUE
;
/* TODO: Raise interrupt */
/* TODO: Figure out what this watch_tag thing is about */
if
(
r
<=
0
)
{
if
(
r
<=
0
)
{
/*
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
uart_transmit, s);
uart_transmit, s);
if (!s->watch_tag) {
if (!s->watch_tag) {
goto buffer_drained;
goto buffer_drained;
}
}
*/
return
FALSE
;
return
FALSE
;
}
}
/*
buffer_drained:
buffer_drained:
s->reg[R_UART_TXDRDY] = 1;
s->reg[R_UART_TXDRDY] = 1;
s->pending_tx_byte = false;
s->pending_tx_byte = false;
return FALSE;
return FALSE;
*/
return FALSE;
return FALSE;
*/
}
}
static
void
uart_cancel_transmit
(
ESP32C3UARTState
*
s
)
static
void
uart_cancel_transmit
(
ESP32C3UARTState
*
s
)
{
{
/* TODO: Figure out what this watch_tag business is about */
/*
/*
if (s->watch_tag) {
if (s->watch_tag) {
g_source_remove(s->watch_tag);
g_source_remove(s->watch_tag);
...
@@ -97,30 +187,29 @@ static void uart_cancel_transmit(ESP32C3UARTState *s)
...
@@ -97,30 +187,29 @@ static void uart_cancel_transmit(ESP32C3UARTState *s)
static
void
uart_write
(
void
*
opaque
,
hwaddr
addr
,
static
void
uart_write
(
void
*
opaque
,
hwaddr
addr
,
uint64_t
value
,
unsigned
int
size
)
uint64_t
value
,
unsigned
int
size
)
{
{
uint8_t
byte
;
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
trace_esp32_c3_uart_write
(
addr
,
value
,
size
);
trace_esp32_c3_uart_write
(
addr
,
value
,
size
);
/* TODO: Check if enabled */
switch
(
addr
)
{
switch
(
addr
)
{
case
A_UART_FIFO
:
case
A_UART_FIFO
:
if
(
s
->
tx_fifo_pos
<
ESP32_C3_UART_FIFO_LENGTH
)
{
/*
s
->
tx_fifo
[
s
->
tx_fifo_pos
]
=
value
;
* FIXME:
s
->
tx_fifo_pos
++
;
* The hardware doesn't allow writing this register.
s
->
pending_tx
=
true
;
* We only allow it here until sending is implemented properly.
}
else
{
*/
/* TODO: Log */
byte
=
(
value
&
R_UART_FIFO_UART_RXFIFO_RD_BYTE_MASK
)
<<
R_UART_FIFO_UART_RXFIFO_RD_BYTE_SHIFT
;
return
;
uart_tx_fifo_push
(
s
,
byte
);
}
uart_transmit
(
NULL
,
G_IO_OUT
,
s
);
uart_transmit
(
NULL
,
G_IO_OUT
,
s
);
break
;
break
;
default:
default:
/* TODO: Log */
qemu_log_mask
(
LOG_UNIMP
,
"Write to unimplemented UART control register may not have any effect
\n
"
);
s
->
regs
[
addr
/
4
]
=
value
;
s
->
regs
[
addr
/
4
]
=
value
;
break
;
break
;
}
}
/* TODO: Update IRQ */
/* TODO: Update IRQ (once interrupt controller is implemented) */
}
}
static
const
MemoryRegionOps
uart_ops
=
{
static
const
MemoryRegionOps
uart_ops
=
{
...
@@ -140,43 +229,40 @@ static void esp32_c3_uart_reset(DeviceState *dev)
...
@@ -140,43 +229,40 @@ static void esp32_c3_uart_reset(DeviceState *dev)
memset
(
s
->
rx_fifo
,
0
,
sizeof
(
s
->
rx_fifo
));
memset
(
s
->
rx_fifo
,
0
,
sizeof
(
s
->
rx_fifo
));
memset
(
s
->
tx_fifo
,
0
,
sizeof
(
s
->
tx_fifo
));
memset
(
s
->
tx_fifo
,
0
,
sizeof
(
s
->
tx_fifo
));
s
->
rx_fifo_pos
=
0
;
s
->
rx_fifo_head
=
0
;
s
->
tx_fifo_pos
=
0
;
s
->
rx_fifo_tail
=
0
;
s
->
tx_fifo_head
=
0
;
s
->
tx_fifo_tail
=
0
;
s
->
pending_tx
=
false
;
s
->
pending_tx
=
false
;
s
->
rx_enabled
=
false
;
s
->
tx_enabled
=
false
;
}
}
static
void
uart_receive
(
void
*
opaque
,
const
uint8_t
*
buf
,
int
size
)
static
void
uart_receive
(
void
*
opaque
,
const
uint8_t
*
buf
,
int
size
)
{
{
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
int
i
;
int
i
;
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
if
(
size
==
0
||
s
->
rx_fifo_pos
>=
ESP32_C3_UART_FIFO_LENGTH
)
{
// TODO: Log
return
;
}
for
(
i
=
0
;
i
<
size
;
i
++
)
{
for
(
i
=
0
;
i
<
size
;
i
++
)
{
uint32_t
pos
=
s
->
rx_fifo_pos
%
ESP32_C3_UART_FIFO_LENGTH
;
uart_rx_fifo_push
(
s
,
buf
[
i
]);
s
->
rx_fifo
[
pos
]
=
buf
[
i
];
s
->
rx_fifo_pos
++
;
}
}
// TODO: Signal RX ready
/* TODO: Raise interrupt */
}
}
static
int
uart_can_receive
(
void
*
opaque
)
static
int
uart_can_receive
(
void
*
opaque
)
{
{
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
ESP32C3UARTState
*
s
=
ESP32_C3_UART
(
opaque
);
/* Does FIFO have space? */
/* Is receiving enabled? */
// TODO: Check whether receiver is enabled
if
(
!
s
->
rx_enabled
)
{
if
(
s
->
rx_fifo_pos
<
ESP32_C3_UART_FIFO_LENGTH
)
{
return
ESP32_C3_UART_FIFO_LENGTH
-
s
->
rx_fifo_pos
;
}
return
0
;
return
0
;
}
}
return
1
;
}
static
void
uart_event
(
void
*
opaque
,
QEMUChrEvent
event
)
static
void
uart_event
(
void
*
opaque
,
QEMUChrEvent
event
)
{
{
// ESP32C3UARTState *s = ESP32_C3_UART(opaque);
// ESP32C3UARTState *s = ESP32_C3_UART(opaque);
...
@@ -208,9 +294,9 @@ static void esp32_c3_uart_init(Object *obj)
...
@@ -208,9 +294,9 @@ static void esp32_c3_uart_init(Object *obj)
static
int
esp32_c3_uart_post_load
(
void
*
opaque
,
int
version_id
)
static
int
esp32_c3_uart_post_load
(
void
*
opaque
,
int
version_id
)
{
{
// ESP32C3UARTState *s = ESP32_C3_UART(opaque);
/* TODO: Send pending bytes */
/*
/*
ESP32C3UARTState *s = ESP32_C3_UART(opaque);
if (s->pending_tx_byte) {
if (s->pending_tx_byte) {
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
...
@@ -229,8 +315,13 @@ static const VMStateDescription esp32_c3_uart_vmstate = {
...
@@ -229,8 +315,13 @@ static const VMStateDescription esp32_c3_uart_vmstate = {
VMSTATE_UINT32_ARRAY
(
regs
,
ESP32C3UARTState
,
ESP32_C3_UART_IOMEM_SIZE_WORDS
),
VMSTATE_UINT32_ARRAY
(
regs
,
ESP32C3UARTState
,
ESP32_C3_UART_IOMEM_SIZE_WORDS
),
VMSTATE_UINT8_ARRAY
(
rx_fifo
,
ESP32C3UARTState
,
ESP32_C3_UART_FIFO_LENGTH
),
VMSTATE_UINT8_ARRAY
(
rx_fifo
,
ESP32C3UARTState
,
ESP32_C3_UART_FIFO_LENGTH
),
VMSTATE_UINT8_ARRAY
(
tx_fifo
,
ESP32C3UARTState
,
ESP32_C3_UART_FIFO_LENGTH
),
VMSTATE_UINT8_ARRAY
(
tx_fifo
,
ESP32C3UARTState
,
ESP32_C3_UART_FIFO_LENGTH
),
VMSTATE_UINT32
(
rx_fifo_pos
,
ESP32C3UARTState
),
VMSTATE_UINT32
(
rx_fifo_head
,
ESP32C3UARTState
),
VMSTATE_UINT32
(
tx_fifo_pos
,
ESP32C3UARTState
),
VMSTATE_UINT32
(
rx_fifo_tail
,
ESP32C3UARTState
),
VMSTATE_UINT32
(
tx_fifo_head
,
ESP32C3UARTState
),
VMSTATE_UINT32
(
tx_fifo_tail
,
ESP32C3UARTState
),
VMSTATE_BOOL
(
rx_enabled
,
ESP32C3UARTState
),
VMSTATE_BOOL
(
tx_enabled
,
ESP32C3UARTState
),
VMSTATE_BOOL
(
pending_tx
,
ESP32C3UARTState
),
VMSTATE_END_OF_LIST
()
VMSTATE_END_OF_LIST
()
}
}
};
};
...
...
This diff is collapsed.
Click to expand it.
hw/char/trace-events
+
7
−
0
View file @
31c5762c
...
@@ -109,3 +109,10 @@ sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %
...
@@ -109,3 +109,10 @@ sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %
# esp32_c3_uart.c
# esp32_c3_uart.c
esp32_c3_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
esp32_c3_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
esp32_c3_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
esp32_c3_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
esp32_c3_uart_tx(void) "UART TX"
esp32_c3_uart_rx(void) "UART RX"
esp32_c3_uart_rx_fifo_read(void) "UART RX FIFO read"
esp32_c3_uart_rx_fifo_underrun(void) "UART RX FIFO underrun, no data"
esp32_c3_uart_tx_fifo_underrun(void) "UART TX FIFO underrun, no data"
esp32_c3_uart_read_disabled(void) "UART read despite RX being disabled"
esp32_c3_uart_write_disabled(void) "UART write despite TX being disabled"
This diff is collapsed.
Click to expand it.
include/hw/char/esp32_c3_uart.h
+
12
−
4
View file @
31c5762c
...
@@ -37,9 +37,13 @@
...
@@ -37,9 +37,13 @@
/* These are all relative to the base address */
/* These are all relative to the base address */
REG32
(
UART_FIFO
,
0x0000
)
/* FIFO read / write operations */
REG32
(
UART_FIFO
,
0x0000
)
/* FIFO read via this register */
FIELD
(
UART_FIFO
,
UART_RXFIFO_RD_BYTE
,
0
,
8
);
REG32
(
UART_CLKDIV
,
0x0014
)
REG32
(
UART_CLKDIV
,
0x0014
)
REG32
(
UART_RX_FILT
,
0x0018
)
REG32
(
UART_RX_FILT
,
0x0018
)
REG32
(
UART_STATUS
,
0x001C
)
FIELD
(
UART_STATUS
,
UART_RXFIFO_CNT
,
0
,
10
)
FIELD
(
UART_STATUS
,
UART_TXFIFO_CNT
,
16
,
10
)
REG32
(
UART_CONF0
,
0x0020
)
REG32
(
UART_CONF0
,
0x0020
)
FIELD
(
UART_CONF0
,
PARITY
,
0
,
1
)
/* Parity config */
FIELD
(
UART_CONF0
,
PARITY
,
0
,
1
)
/* Parity config */
FIELD
(
UART_CONF0
,
PARITY_EN
,
1
,
1
)
/* Parity enable */
FIELD
(
UART_CONF0
,
PARITY_EN
,
1
,
1
)
/* Parity enable */
...
@@ -55,12 +59,16 @@ typedef struct {
...
@@ -55,12 +59,16 @@ typedef struct {
MemoryRegion
iomem
;
/* Config registers memory region */
MemoryRegion
iomem
;
/* Config registers memory region */
uint32_t
regs
[
ESP32_C3_UART_IOMEM_SIZE_WORDS
];
/* Actual contents of config registers */
uint32_t
regs
[
ESP32_C3_UART_IOMEM_SIZE_WORDS
];
/* Actual contents of config registers */
MemoryRegion
fifo
;
/* FIFO RAM memory region */
MemoryRegion
fifo
;
/*
UART
FIFO RAM memory region */
uint8_t
rx_fifo
[
ESP32_C3_UART_FIFO_LENGTH
];
/* RX FIFO RAM */
uint8_t
rx_fifo
[
ESP32_C3_UART_FIFO_LENGTH
];
/* RX FIFO RAM */
uint8_t
tx_fifo
[
ESP32_C3_UART_FIFO_LENGTH
];
/* TX FIFO RAM */
uint8_t
tx_fifo
[
ESP32_C3_UART_FIFO_LENGTH
];
/* TX FIFO RAM */
unsigned
int
rx_fifo_pos
;
/* How many bytes are waiting in RX FIFO */
unsigned
int
rx_fifo_head
;
/* Head of RX FIFO (bytes are appended here) */
unsigned
int
tx_fifo_pos
;
/* How many bytes are waiting in TX FIFO */
unsigned
int
rx_fifo_tail
;
/* Tail of RX FIFO (bytes are read from here) */
unsigned
int
tx_fifo_head
;
/* Head of TX FIFO (bytes are appended here) */
unsigned
int
tx_fifo_tail
;
/* Tail of TX FIFO (bytes are read from here) */
bool
rx_enabled
;
bool
tx_enabled
;
bool
pending_tx
;
bool
pending_tx
;
}
ESP32C3UARTState
;
}
ESP32C3UARTState
;
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment