Skip to content

Commit 434b7d8

Browse files
authored
ports/cheriot-rtos: Merge pull request #2 from JakeTrevor/cheriot-dev
Added I2C and UART implementations for sonata.
2 parents 14251ff + cdaadba commit 434b7d8

File tree

11 files changed

+630
-66
lines changed

11 files changed

+630
-66
lines changed

ports/cheriot-rtos/Makefile

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,36 +51,42 @@ SRC_C = mp_entry.c \
5151
shared/runtime/pyexec.c \
5252
$(BUILD)/_frozen_mpy.c \
5353
machine_pin.c \
54-
machine_spi.c
54+
machine_spi.c \
55+
machine_i2c.c
5556

56-
SRC_CXX =
57+
SRC_CXX =
5758

58-
SRC_QSTR += shared/readline/readline.c shared/runtime/pyexec.c mp_entry.c machine_pin.c machine_spi.c
59+
SRC_QSTR += shared/readline/readline.c shared/runtime/pyexec.c mp_entry.c machine_pin.c machine_spi.c machine_i2c.c
5960

6061
SRC_HAL_C = shared/runtime/stdout_helpers.c
61-
SRC_HAL_CXX = uart_core.cpp
62+
SRC_HAL_CXX = uart_core.cpp hal/i2c.cpp hal/uart.cpp hal/timer.cpp
6263

6364
SRC_MAIN_C =
6465
SRC_MAIN_CXX = main.cpp
6566

66-
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
67-
OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
68-
OBJ += $(PY_O)
67+
OBJ_VM += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
68+
OBJ_VM += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
69+
OBJ_VM += $(PY_O)
6970

7071
OBJ_HAL += $(addprefix $(BUILD)/, $(SRC_HAL_C:.c=.o))
7172
OBJ_HAL += $(addprefix $(BUILD)/, $(SRC_HAL_CXX:.cpp=.o))
7273

7374
OBJ_MAIN += $(addprefix $(BUILD)/, $(SRC_MAIN_C:.c=.o))
7475
OBJ_MAIN += $(addprefix $(BUILD)/, $(SRC_MAIN_CXX:.cpp=.o))
76+
77+
OBJ += $(OBJ_VM)
78+
OBJ += $(OBJ_HAL)
79+
OBJ += $(OBJ_MAIN)
7580

76-
$(OBJ): CFLAGS += -DMP_VM_COMP -cheri-compartment=mp_vm
81+
$(OBJ_VM): CFLAGS += -DMP_VM_COMP -cheri-compartment=mp_vm
7782
$(OBJ_HAL): CFLAGS += -cheri-compartment=mp_hal
7883
$(OBJ_MAIN): CFLAGS += -cheri-compartment=main
7984
$(BUILD)/mp_entry.o: CFLAGS += -UCHERIOT_NO_AMBIENT_MALLOC
85+
$(BUILD)/hal/i2c.o: CFLAGS += -Wno-unused-variable
8086

8187
all: $(BUILD)/micropython.uf2
8288

83-
all_objects : $(OBJ) $(OBJ_HAL) $(OBJ_MAIN)
89+
all_objects : $(OBJ_VM) $(OBJ_HAL) $(OBJ_MAIN)
8490
.PHONY: all all_objects
8591

8692
$(BUILD)/_frozen_mpy.c: $(TOP)/tests/frozen/frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h
@@ -90,7 +96,7 @@ $(BUILD)/_frozen_mpy.c: $(TOP)/tests/frozen/frozentest.mpy $(BUILD)/genhdr/qstrd
9096
$(BUILD)/xmake.lua: xmake.lua.top xmake.lua.bottom
9197
cat xmake.lua.top > $@
9298
echo "compartment(\"mp_vm\")" >> $@
93-
for OFILE in $(patsubst $(BUILD)/%,%,$(OBJ)) ; do echo " add_files(\"$$OFILE\", {rule = \"utils.merge.object\"})" >> $@ ; done
99+
for OFILE in $(patsubst $(BUILD)/%,%,$(OBJ_VM)) ; do echo " add_files(\"$$OFILE\", {rule = \"utils.merge.object\"})" >> $@ ; done
94100
echo "compartment(\"mp_hal\")" >> $@
95101
for OFILE in $(patsubst $(BUILD)/%,%,$(OBJ_HAL)) ; do echo " add_files(\"$$OFILE\", {rule = \"utils.merge.object\"})" >> $@ ; done
96102
echo "compartment(\"main\")" >> $@

ports/cheriot-rtos/hal/i2c.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <stdio.h>
2+
#include <platform-i2c.hh>
3+
4+
#include "mphalport.h"
5+
6+
void MP_HAL_FUNC i2c_setup(volatile OpenTitanI2c *i2c, uint32_t freq_kHz) {
7+
i2c->reset_fifos();
8+
i2c->host_mode_set();
9+
i2c->speed_set(freq_kHz);
10+
}
11+
12+
bool MP_HAL_FUNC i2c_blocking_read(volatile OpenTitanI2c *i2c, uint8_t addr, uint8_t *buf, uint32_t len) {
13+
return i2c->blocking_read(addr, buf, len);
14+
}
15+
16+
bool MP_HAL_FUNC i2c_check_success(volatile OpenTitanI2c *i2c) {
17+
while (!i2c->format_is_empty()) {
18+
}
19+
if (i2c->interrupt_is_asserted(OpenTitanI2cInterrupt::Nak)) {
20+
i2c->interrupt_clear(OpenTitanI2cInterrupt::Nak);
21+
return false;
22+
}
23+
return true;
24+
}
25+
26+
bool MP_HAL_FUNC i2c_blocking_write(volatile OpenTitanI2c *i2c, uint8_t addr, uint8_t *buf, uint32_t len, bool skipStop) {
27+
i2c->blocking_write(addr, buf, len, skipStop);
28+
return i2c_check_success(i2c);
29+
}
30+
31+
32+
bool MP_HAL_FUNC i2c_send_address(volatile OpenTitanI2c *i2c, uint8_t addr) {
33+
i2c->blocking_write_byte(OpenTitanI2c::FormatDataStart | OpenTitanI2c::FormatDataStop | (addr << 1) | 1u);
34+
return i2c_check_success(i2c);
35+
}

ports/cheriot-rtos/hal/timer.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include <cheri.hh>
2+
#include <stdint.h>
3+
#include <utils.hh>
4+
5+
#include "mphalport.h"
6+
7+
class StandardClint : private utils::NoCopyNoMove
8+
{
9+
public:
10+
/**
11+
* Initialise the interface.
12+
*/
13+
static void init() {
14+
// This needs to be csr_read(mhartid) if we support multicore
15+
// systems, but we don't plan to any time soon.
16+
constexpr uint32_t HartId = 0;
17+
18+
auto setField = [&](auto &field, size_t offset, size_t size) {
19+
CHERI::Capability capability{MMIO_CAPABILITY(uint32_t, clint)};
20+
capability.address() += offset;
21+
capability.bounds() = size;
22+
field = capability;
23+
};
24+
setField(pmtimer, StandardClint::ClintMtime, 2 * sizeof(uint32_t));
25+
setField(pmtimercmp,
26+
StandardClint::ClintMtimecmp + HartId * 8,
27+
2 * sizeof(uint32_t));
28+
}
29+
30+
static uint64_t time() {
31+
// The timer is little endian, so the high 32 bits are after the low 32
32+
// bits. We can't do atomic 64-bit loads and so we have to read these
33+
// separately.
34+
volatile uint32_t *timerHigh = pmtimer + 1;
35+
uint32_t timeLow, timeHigh;
36+
37+
// Read the current time. Loop until the high 32 bits are stable.
38+
do
39+
{
40+
timeHigh = *timerHigh;
41+
timeLow = *pmtimer;
42+
} while (timeHigh != *timerHigh);
43+
return (uint64_t(timeHigh) << 32) | timeLow;
44+
}
45+
46+
private:
47+
#ifdef IBEX_SAFE
48+
/**
49+
* The Ibex-SAFE platform doesn't implement a complete CLINT, only the
50+
* timer part (which is all that we use). Its offsets within the CLINT
51+
* region are different.
52+
*/
53+
static constexpr size_t ClintMtime = 0x10;
54+
static constexpr size_t ClintMtimecmp = 0x18;
55+
#else
56+
/**
57+
* The standard RISC-V CLINT is a large memory-mapped device and places the
58+
* timers a long way in.
59+
*/
60+
static constexpr size_t ClintMtimecmp = 0x4000U;
61+
static constexpr size_t ClintMtime = 0xbff8U;
62+
#endif
63+
64+
static inline volatile uint32_t *pmtimercmp;
65+
static inline volatile uint32_t *pmtimer;
66+
};
67+
68+
using TimerCore = StandardClint;
69+
70+
71+
uint64_t MP_HAL_FUNC get_time() {
72+
StandardClint::init();
73+
return StandardClint::time();
74+
}
75+
76+
// void MP_HAL_FUNC set_next(uint64_t next_time) {
77+
// StandardClint::init();
78+
// StandardClint::setnext(next_time);
79+
// }
80+
81+
// void MP_HAL_FUNC clear() {
82+
// StandardClient::clear();
83+
// }

ports/cheriot-rtos/hal/timer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "py/obj.h"
2+
#include "mphalport.h"
3+
4+
#define CLOCK_FREQ_KHZ (50000)
5+
#define MS_TO_CLOCK_CYCLES(x) (x * CLOCK_FREQ_KHZ) // clock 50mHz
6+
7+
uint64_t MP_HAL_FUNC get_time();

ports/cheriot-rtos/hal/uart.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <platform-uart.hh>
2+
3+
#include "mphalport.h"
4+
#include "timer.h"
5+
6+
uint8_t MP_HAL_FUNC uart_get_rx_level(volatile OpenTitanUart *block) {
7+
return block->receive_fifo_level();
8+
}
9+
10+
uint8_t MP_HAL_FUNC uart_get_tx_level(volatile OpenTitanUart *block) {
11+
return block->transmit_fifo_level();
12+
}
13+
14+
bool MP_HAL_FUNC uart_is_readable(volatile OpenTitanUart *block) {
15+
return block->can_read();
16+
}
17+
18+
bool MP_HAL_FUNC uart_is_writable(volatile OpenTitanUart *block) {
19+
return block->can_write();
20+
}
21+
22+
bool MP_HAL_FUNC uart_timeout_read(volatile OpenTitanUart *block, uint8_t *out, uint32_t timeout_ms) {
23+
uint32_t t_end = get_time() + MS_TO_CLOCK_CYCLES(timeout_ms);
24+
25+
while (!block->can_read()) {
26+
if (get_time() > t_end) {
27+
return false;
28+
}
29+
}
30+
31+
*out = block->readData;
32+
return true;
33+
}
34+
35+
void MP_HAL_FUNC uart_blocking_write(volatile OpenTitanUart *block, uint8_t data) {
36+
block->blocking_write(data);
37+
}
38+
39+
void MP_HAL_FUNC uart_init(volatile OpenTitanUart *block, uint32_t baudrate) {
40+
block->init(baudrate);
41+
}

ports/cheriot-rtos/machine_i2c.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include <stdio.h>
2+
3+
#include "py/obj.h"
4+
#include "py/runtime.h"
5+
#include "extmod/modmachine.h"
6+
7+
#include "mphalport.h"
8+
9+
#define I2C_DEFAULT_FREQ (400000)
10+
11+
#define SPI_0_ADDR (0x80200000)
12+
#define SPI_1_ADDR (0x80201000)
13+
14+
15+
typedef struct _machine_i2c_obj_t {
16+
mp_obj_base_t base;
17+
volatile open_titan_i2c_t *i2c_block;
18+
} machine_i2c_obj_t;
19+
20+
21+
static void machine_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
22+
machine_i2c_obj_t *self = (machine_i2c_obj_t *)MP_OBJ_TO_PTR(self_in);
23+
const char *name;
24+
25+
switch ((ptraddr_t)self->i2c_block) {
26+
case SPI_0_ADDR:
27+
name = "0";
28+
break;
29+
case SPI_1_ADDR:
30+
name = "1";
31+
break;
32+
default:
33+
name = "Unknown SPI device";
34+
break;
35+
}
36+
37+
mp_printf(print, "I2C(%s)", name);
38+
}
39+
40+
41+
static volatile open_titan_i2c_t *get_i2c_block(uint32_t id) {
42+
switch (id) {
43+
case 0:
44+
return MMIO_CAPABILITY(open_titan_i2c_t, i2c0);
45+
case 1:
46+
return MMIO_CAPABILITY(open_titan_i2c_t, i2c1);
47+
default:
48+
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Unknown i2c device \"%d\""), id);
49+
}
50+
}
51+
52+
mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
53+
enum { ARG_id, ARG_freq, ARG_scl, ARG_sda, ARG_timeout };
54+
static const mp_arg_t allowed_args[] = {
55+
{MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT},
56+
{MP_QSTR_freq, MP_ARG_INT, {.u_int = I2C_DEFAULT_FREQ}},
57+
{MP_QSTR_scl, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
58+
{MP_QSTR_sda, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
59+
{MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
60+
};
61+
62+
// Parse args.
63+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
64+
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args),
65+
allowed_args, args);
66+
67+
if (args[ARG_timeout].u_obj != -1) {
68+
mp_raise_NotImplementedError(
69+
MP_ERROR_TEXT("explicit choice of timeout is not implemented"));
70+
}
71+
72+
73+
if ((args[ARG_scl].u_obj != MP_OBJ_NULL) ||
74+
(args[ARG_sda].u_obj != MP_OBJ_NULL)) {
75+
mp_raise_NotImplementedError(
76+
MP_ERROR_TEXT("explicit choice of sck/sda is not implemented"));
77+
}
78+
79+
volatile open_titan_i2c_t *block = get_i2c_block(args[ARG_id].u_int);
80+
uint32_t freq_kHz = args[ARG_freq].u_int / 1000;
81+
82+
i2c_setup(block, freq_kHz);
83+
84+
machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t);
85+
self->i2c_block = block;
86+
self->base.type = &machine_i2c_type;
87+
88+
return MP_OBJ_FROM_PTR(self);
89+
}
90+
91+
92+
static int machine_i2c_transfer_single(mp_obj_base_t *self_in, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags) {
93+
machine_i2c_obj_t *self = (machine_i2c_obj_t *)MP_OBJ_TO_PTR(self_in);
94+
bool stop = 0 != (flags & MP_MACHINE_I2C_FLAG_STOP);
95+
96+
bool success;
97+
98+
if (len == 0) {
99+
success = i2c_send_address(self->i2c_block, addr);
100+
101+
} else if (flags & MP_MACHINE_I2C_FLAG_READ) {
102+
success = i2c_blocking_read(self->i2c_block, addr, buf, len);
103+
104+
} else {
105+
success = i2c_blocking_write(self->i2c_block, addr, buf, len, !stop);
106+
}
107+
return success ? len : -5;
108+
}
109+
110+
static const mp_machine_i2c_p_t machine_i2c_p = {
111+
.transfer = mp_machine_i2c_transfer_adaptor,
112+
.transfer_single = machine_i2c_transfer_single,
113+
};
114+
115+
MP_DEFINE_CONST_OBJ_TYPE(
116+
machine_i2c_type,
117+
MP_QSTR_I2C,
118+
MP_TYPE_FLAG_NONE,
119+
make_new, machine_i2c_make_new,
120+
print, machine_i2c_print,
121+
protocol, &machine_i2c_p,
122+
locals_dict, &mp_machine_i2c_locals_dict
123+
);

0 commit comments

Comments
 (0)