summaryrefslogtreecommitdiff
path: root/uart.c
blob: e53978bc64e792076d03dec68f413131688c4a69 (plain)
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
/*
 * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
 * Copyright (C) 2010 chysun2000@gmail.com
 *
 * This file is part of nios2sim-ng.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#include <stdio.h>
#include <stdlib.h>

#include "nios2sim-ng.h"
#include "device.h"
#include "uart.h"

#define uart_printf(fmt, args...)	fprintf(stdout, fmt, ##args)

struct uart {
	struct io_register regs[UART_REG_COUNT];
	bool has_rx_data;
	bool has_tx_data;
};

static const uint32_t uart_valid_mask[UART_REG_COUNT] = {
	0x000001FF,	/* rxdata */
	0x000001FF,	/* txdata */
	0x00001FFF,	/* status */
	0x00001FFF,	/* control */
	0x0000FFFF,	/* divisor */
	0x000001FF,	/* endofpacket */
};

static const uint32_t uart_readonly_mask[UART_REG_COUNT] = {
	0x000001FF,	/* rxdata */
	0x00000000,	/* txdata */
	0x00000000,	/* status */
	0x00000000,	/* control */
	0x00000000,	/* divisor */
	0x00000000,	/* endofpacket */
};

static int uart_init(struct device *dev)
{
	struct uart *u;
	struct io_register *regs;
	unsigned int i;

	u = malloc(sizeof(struct uart));
	if (unlikely(u == NULL))
		return -1;

	regs = u->regs;
	for (i = 0; i < UART_REG_COUNT; i++) {
		io_register_init(&regs[i],
				 UART_BASE + REG_TO_OFF(i),
				 uart_valid_mask[i],
				 uart_readonly_mask[i],
				 0);
	}

	u->has_rx_data = false;
	u->has_tx_data = false;

	dev->priv = u;

	return 0;
}

static size_t uart_read(struct device *dev, uint32_t addr, uint8_t *data, size_t count)
{
	struct uart *u = dev->priv;
	struct io_register *regs = u->regs;
	unsigned int reg;
	uint32_t val;
	size_t ret;

	trace("count=%zu\n", count);

	if (addr < dev->base || addr >= dev->base + dev->size)
		return 0;

	reg = OFF_TO_REG(addr - dev->base);
	val = io_register_read(&regs[reg]);

	if (reg == UART_RXDATA_REG) {
		u->has_rx_data = false;
		regs[UART_STATUS_REG].value &= ~UART_CONTROL_RRDY_MASK;
	}

	return count;
}

static size_t uart_write(struct device *dev, uint32_t addr, uint8_t *data, size_t count)
{
	struct uart *u = dev->priv;
	struct io_register *regs = u->regs;
	unsigned int reg;
	uint32_t val;
	size_t ret;

	trace("count=%zu\n", count);

	if (addr < dev->base || addr >= dev->base + dev->size)
		return 0;


	return count;
}

static bool uart_has_irq(struct device *dev)
{
	struct uart *u = dev->priv;
	uint32_t ctrl = u->regs[UART_CONTROL_REG].value;
	uint32_t status = u->regs[UART_STATUS_REG].value;

	/* Check TX ready IRQ */
	if ((ctrl & UART_CONTROL_TRDY_MASK) && (status & UART_STATUS_TRDY_MASK))
		return true;

	/* Check RX ready IRQ */
	if ((ctrl & UART_CONTROL_RRDY_MASK) && (status & UART_STATUS_RRDY_MASK))
		return true;

	return false;
}

static void uart_simulate(struct device *dev)
{
	struct uart *u = dev->priv;
	struct io_register *regs = u->regs;

	if (u->has_tx_data) {
		regs[UART_STATUS_REG].value &= ~UART_STATUS_TRDY_MASK;
	}

	if (u->has_rx_data) {
	}
}

struct device uart_core = {
	.name		= "UART Core",
	.base		= UART_BASE,
	.size		= UART_SIZE,
	.irq_mask	= IRQ_TO_MASK(IRQ_UART),

	.init		= uart_init,
	.is_dev_addr	= NULL,	/* use generic */
	.read		= uart_read,
	.write		= uart_write,
	.has_irq	= uart_has_irq,
	.simulate	= uart_simulate,
};