-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added new logging backend - for spinel protocol #2
base: master
Are you sure you want to change the base?
Conversation
67b73ba
to
4276c3e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I found some issue - or I am missing something
subsys/logging/log_backend_spinel.c
Outdated
@@ -0,0 +1,103 @@ | |||
/* | |||
* Copyright (c) 2018 Nordic Semiconductor ASA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix copyright
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
subsys/logging/log_backend_spinel.c
Outdated
#define CONFIG_LOG_BACKEND_SPINEL_BUFFER_SIZE 0 | ||
#endif | ||
|
||
static u8_t char_buf[CONFIG_LOG_BACKEND_SPINEL_BUFFER_SIZE]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to upmerge. Zephyr var types were removed. use stdint instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
subsys/logging/log_backend_spinel.c
Outdated
} | ||
|
||
static void sync_string(const struct log_backend *const backend, | ||
struct log_msg_ids src_level, u32_t timestamp, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if alignment is wrong here or is it just github display issue
subsys/logging/log_backend_spinel.c
Outdated
static void put(const struct log_backend *const backend, | ||
struct log_msg *msg) | ||
{ | ||
// prevent adding CRLF, which may crash spinel decoding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
run the checkpatch script on the files. I'm not sure c++ comments are allowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did and there were no errors, but as Łukasz Maciejończyk wrote it is not allowed, so was fixed.
subsys/logging/log_backend_spinel.c
Outdated
log_backend_std_dropped(&log_output, cnt); | ||
} | ||
|
||
__attribute__((weak)) void otPlatLog(int aLogLevel, int aLogRegion, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid of this;) But leave it for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a weak definition in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this, because I couldn't find clear way to include logging.h file, where otPlatLog method declaration is located. Moreover I thought that I shouldn't provide OpenThread specific includes inside very general Zephyr logging directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see an issue with introducing a header if we aleady use an OT function in the file, if that's the case. I also don't see why shouldn't it work (for instance logging.c
use this header).
Nonetheless, I still don't quite understand why a weak definition is provided here instead of a function declaration:
void otPlatLog(int aLogLevel, int aLogRegion, const char *aFormat, ...);
(which would not be needed if the header was provided).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I did, as you said and it works. I'm not sure why I was having a problems. Probably I had some weird state because I messed up something in include paths or maybe switching between branches. Still have to learn project structure and using git...
@@ -44,7 +49,6 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, | |||
case OT_LOG_LEVEL_WARN: | |||
LOG_WRN("%s", log_strdup(logString)); | |||
break; | |||
case OT_LOG_LEVEL_NOTE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why was OT_LOG_LEVEL_NOTE removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually both changes are not mine and I don't know how they get there. I think that I did something wrong during cherry picking of file revision, but it is fixed now
@@ -19,13 +19,18 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); | |||
|
|||
#define LOG_PARSE_BUFFER_SIZE 128 | |||
|
|||
#ifndef OPENTHREAD_CONFIG_LOG_OUTPUT | |||
#define OPENTHREAD_CONFIG_LOG_OUTPUT CONFIG_LOG_OUTPUT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is it used for? Cant find any use of it in the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used to provide (or not) implementation of otPlatLog method by Zephyr. If we want to use Spinel backend such implementation has to be turned off, because it is already provided by ncp_base.cpp file in ncp component and multiple definition error occur.
subsys/logging/Kconfig
Outdated
@@ -44,6 +44,19 @@ config LOG_DEFAULT_LEVEL | |||
- 3 INFO, default to write LOG_LEVEL_INFO | |||
- 4 DEBUG, default to write LOG_LEVEL_DBG | |||
|
|||
config LOG_OUTPUT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is that used? Is it some macro magic? Can't find any usage of it except the one unused macro.
ad3e5a3
to
845f85a
Compare
subsys/logging/Kconfig
Outdated
@@ -424,6 +437,41 @@ config LOG_BACKEND_RTT_FORCE_PRINTK | |||
|
|||
endif # LOG_BACKEND_RTT | |||
|
|||
if LOG_BACKEND_SPINEL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does that work? the if is above it's symbol definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it's not. I miss clicked and it worked for me probably thanks for cmake cache. Fixed
subsys/logging/Kconfig
Outdated
help | ||
Sets log level | ||
|
||
- 0 NONE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this could also be converted to options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
0605357
to
31944f1
Compare
5b99e8a
to
3608294
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty ok for me, you might consider requesting a review from @nordic-krch before going upstream, he's our logging subsystem expert. He'll review it eventually anyway.
@@ -19,6 +19,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); | |||
|
|||
#define LOG_PARSE_BUFFER_SIZE 128 | |||
|
|||
#if !CONFIG_LOG_BACKEND_SPINEL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be cleaner to disable logging.c
build at the CMake level (make it conditional with zephyr_library_sources_ifndef
), there's really no point building this file in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very smart way. I find it really useful to remember :) Done
subsys/logging/Kconfig
Outdated
config LOG_BACKEND_SPINEL | ||
bool "Enable Spinel protocol backend" | ||
depends on !LOG_BACKEND_UART | ||
default n |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for default n
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
subsys/logging/Kconfig
Outdated
@@ -424,6 +424,51 @@ config LOG_BACKEND_RTT_FORCE_PRINTK | |||
|
|||
endif # LOG_BACKEND_RTT | |||
|
|||
config LOG_BACKEND_SPINEL | |||
bool "Enable Spinel protocol backend" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd mention here that this backend is dedicated to use with OpenThread, it might be not clear what Spinnel actually is. Here or in the help message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
subsys/logging/Kconfig
Outdated
@@ -424,6 +424,51 @@ config LOG_BACKEND_RTT_FORCE_PRINTK | |||
|
|||
endif # LOG_BACKEND_RTT | |||
|
|||
config LOG_BACKEND_SPINEL | |||
bool "Enable Spinel protocol backend" | |||
depends on !LOG_BACKEND_UART |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we shall also add dependency to OpenThread (NET_L2_OPENTHREAD
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
depends on !LOG_BACKEND_UART
isn't it possible to have spinel on different UART and console/log on another?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it is. I changed dependency to turn on Spinel backend only if UART backend is disabled or is enabled on another UART device than spinel. Is it ok now? I did some tests, using both backends at once and it seems to work properly.
subsys/logging/log_backend_spinel.c
Outdated
log_backend_std_dropped(&log_output, cnt); | ||
} | ||
|
||
__attribute__((weak)) void otPlatLog(int aLogLevel, int aLogRegion, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a weak definition in the first place?
b2b0530
to
069e1a1
Compare
subsys/logging/Kconfig
Outdated
@@ -424,6 +424,51 @@ config LOG_BACKEND_RTT_FORCE_PRINTK | |||
|
|||
endif # LOG_BACKEND_RTT | |||
|
|||
config LOG_BACKEND_SPINEL | |||
bool "Enable Spinel protocol backend" | |||
depends on !LOG_BACKEND_UART |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
depends on !LOG_BACKEND_UART
isn't it possible to have spinel on different UART and console/log on another?
subsys/logging/log_backend_spinel.c
Outdated
const int log_region_platform = 12; | ||
|
||
otPlatLog(CONFIG_LOG_BACKEND_SPINEL_LEVEL, log_region_platform, | ||
"%s", data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please improve indentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Can you tell me where to find some indentation rules? As I can see in other files done by Nordic, when breaking line of method arguments, number of tabs is quite different. Sometimes its 1 tab, another 3 or 4.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure it is written there, but when you break line on function params you just align to the first parameter unless it is not possible
subsys/logging/log_backend_spinel.c
Outdated
/* assuming SPINEL backend logs as platform region */ | ||
const int log_region_platform = 12; | ||
|
||
otPlatLog(CONFIG_LOG_BACKEND_SPINEL_LEVEL, log_region_platform, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see that you don't do any reconfiguration when panic is called. Can otPlatLog
be called from isr and is it synchronous? when system enters panic mode, it is expected that all log operations becomes synchronous without any context switching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is fixed, please take a look at this. It was decided to add synchronous UART transmission in the Zephyr ot platform uart.c file, as it wasn't implemented. OT in its assumption doesn't use otPlatLog method from the isr, so it doesn't make a problem. Zephyr may do that and otPlatLog for NCP cannot be called from isr, so that's why after consultation with Łukasz Duda, we decided to put raw bytes without encoding on the interface in the panic mode.
af8db6b
to
e9545df
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice contribution, I have left few comments
subsys/logging/log_backend_spinel.c
Outdated
static int write(uint8_t *data, size_t length, void *ctx) | ||
{ | ||
/* assuming SPINEL backend logs as platform region */ | ||
const int log_region_platform = 12; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using OT_LOG_REGION_PLATFORM enum value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
subsys/logging/log_backend_spinel.c
Outdated
* cannot be used, because it cannot be called from interrupt. | ||
* In such situation raw data bytes without encoding are send. | ||
*/ | ||
otPlatUartSetPanicMode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uart panic function should be called once in panic() body
} | ||
|
||
static void panic(struct log_backend const *const backend) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap every unused argument with ARG_UNUSED()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -208,7 +210,14 @@ otError otPlatUartSend(const u8_t *aBuf, u16_t aBufLength) | |||
size_t cnt = ring_buf_put(ot_uart.tx_ringbuf, aBuf, aBufLength); | |||
|
|||
if (atomic_set(&(ot_uart.tx_busy), 1) == 0) { | |||
uart_irq_tx_enable(ot_uart.dev); | |||
if(is_panic_mode){ | |||
/* In panic mode all data have to be send imidiatelly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'immediately' typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -208,7 +210,14 @@ otError otPlatUartSend(const u8_t *aBuf, u16_t aBufLength) | |||
size_t cnt = ring_buf_put(ot_uart.tx_ringbuf, aBuf, aBufLength); | |||
|
|||
if (atomic_set(&(ot_uart.tx_busy), 1) == 0) { | |||
uart_irq_tx_enable(ot_uart.dev); | |||
if(is_panic_mode){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix spaces in this block - space after if, before bracket and after 'else'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return result; | ||
} | ||
|
||
void otPlatUartSetPanicMode(void) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of creating OT-like function let's create Zephyr - specific function like platformUartProcess(), e.g. platformUartPanic(), it's declaration can be added to zephyr/subsys/net/lib/openthread/platform/platform-zephyr.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
subsys/logging/log_backend_spinel.c
Outdated
/* assuming SPINEL backend logs as platform region */ | ||
const int log_region_platform = 12; | ||
|
||
if(is_panic_mode()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix spaces in this block - space after if, before bracket and after 'else'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
e9545df
to
75a2780
Compare
const u8_t *data; | ||
otError result = OT_ERROR_NONE; | ||
|
||
len = ring_buf_get_claim(ot_uart.tx_ringbuf, (u8_t **)&data, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not exactly my area of expertise, but shouldn't we call ring_buf_get_finish
after we process the data? In the API docs we have:
Once data is processed it can be freed using @ref ring_buf_get_finish.
Also, shouldn't we call this in a loop until ring_buf_is_empty()
returns true in order to fully flush the buffer? IIUC ring_buf_get_claim
returns the largest continuous buffer it can, but it isn't necessarily all of the data available in the buffer (in case the data wraps). At least, that's what documentation suggests (and brief look into the code confirms that):
@return Number of valid bytes in the provided buffer which can be smaller than requested if there is not enough free space or buffer wraps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to documentation, you are right about the need to free space and call claim operation in loop. So I implemented do while() loop, which should solve the problem, please verify it. If it comes to usage the ring_buf_is_empty() method, it leads to lock in infinite loop, as buffer is not empty even when ring_buf_get_claim() can't get anything from it and returns 0 bytes every time. I'm not sure why is it happening, so I look to the ring buffer tests, where buffer empty is checked by trying to claim something and getting 0 bytes in result and ring_buf_is_empty() is not used for that. I thought about leaving it implemented this way, as it is compatible with tests, but also to contact with verification team to ask about this problem. Is this ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is so, then indeed it seems something fishy is going on with ring_buf_is_empty()
function, probably worth an Zephyr issue to create. Nonetheless, current solution looks fine to me.
subsys/logging/log_backend_spinel.c
Outdated
static int write(uint8_t *data, size_t length, void *ctx); | ||
|
||
LOG_OUTPUT_DEFINE(log_output, write, | ||
char_buf, sizeof(char_buf)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Do we need to break the line here, I guess it should all fit into a single line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
75a2780
to
74b6acb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alignment seems to be off in some places.
memset(char_buf, '\0', sizeof(char_buf)); | ||
} | ||
|
||
static void panic(struct log_backend const *const backend) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Shouldn't panic function flush the uart automatically?
c0516ab
to
07ef131
Compare
|
||
do { | ||
len = ring_buf_get_claim(ot_uart.tx_ringbuf, (u8_t **)&data, | ||
ot_uart.tx_ringbuf->size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: alignment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
It seems something went wrong with the reabase (I guess?), there are commits in here that should not be. |
07ef131
to
8c5fdd9
Compare
Yes, I accidentally pushed also not mine commits. It is fixed now. |
8c5fdd9
to
d8f7210
Compare
New logging backend that can be used by NCP architecture. Signed-off-by: Kamil Kasperczyk <[email protected]>
d8f7210
to
ea75dae
Compare
This makes the gatt metrics also available for gatt write-without-rsp-cb so it now prints the rate of each write: uart:~$ gatt write-without-response-cb 1e ff 10 10 Write #1: 16 bytes (0 bps) Write #2: 32 bytes (3445948416 bps) Write #3: 48 bytes (2596929536 bps) Write #4: 64 bytes (6400 bps) Write #5: 80 bytes (8533 bps) Write #6: 96 bytes (10666 bps) Write #7: 112 bytes (8533 bps) Write #8: 128 bytes (9955 bps) Write zephyrproject-rtos#9: 144 bytes (11377 bps) Write zephyrproject-rtos#10: 160 bytes (7680 bps) Write zephyrproject-rtos#11: 176 bytes (8533 bps) Write zephyrproject-rtos#12: 192 bytes (9386 bps) Write Complete (err 0) Write zephyrproject-rtos#13: 208 bytes (8533 bps) Write zephyrproject-rtos#14: 224 bytes (9244 bps) Write zephyrproject-rtos#15: 240 bytes (9955 bps) Write zephyrproject-rtos#16: 256 bytes (8000 bps) Signed-off-by: Luiz Augusto von Dentz <[email protected]>
The _ldiv5() is an optimized divide-by-5 function that is smaller and faster than the generic libgcc implementation. Yet it can be made even smaller and faster with this replacement implementation based on a reciprocal multiplication plus some tricks. For example, here's the assembly from the original code on ARM: _ldiv5: ldr r3, [r0] movw ip, zephyrproject-rtos#52429 ldr r1, [r0, #4] movt ip, 52428 adds r3, r3, #2 push {r4, r5, r6, r7, lr} mov lr, #0 adc r1, r1, lr adds r2, lr, lr umull r7, r6, ip, r1 lsr r6, r6, #2 adc r7, r6, r6 adds r2, r2, r2 adc r7, r7, r7 adds r2, r2, lr adc r7, r7, r6 subs r3, r3, r2 sbc r7, r1, r7 lsr r2, r3, #3 orr r2, r2, r7, lsl zephyrproject-rtos#29 umull r2, r1, ip, r2 lsr r2, r1, #2 lsr r7, r1, zephyrproject-rtos#31 lsl r1, r2, #3 adds r4, lr, r1 adc r5, r6, r7 adds r2, r1, r1 adds r2, r2, r2 adds r2, r2, r1 subs r2, r3, r2 umull r3, r2, ip, r2 lsr r2, r2, #2 adds r4, r4, r2 adc r5, r5, #0 strd r4, [r0] pop {r4, r5, r6, r7, pc} And here's the resulting assembly with this commit applied: _ldiv5: push {r4, r5, r6, r7} movw r4, zephyrproject-rtos#13107 ldr r6, [r0] movt r4, 13107 ldr r1, [r0, #4] mov r3, #0 umull r6, r7, r6, r4 add r2, r4, r4, lsl #1 umull r4, r5, r1, r4 adds r1, r6, r2 adc r2, r7, r2 adds ip, r6, r4 adc r1, r7, r5 adds r2, ip, r2 adc r2, r1, r3 adds r2, r4, r2 adc r3, r5, r3 strd r2, [r0] pop {r4, r5, r6, r7} bx lr So we're down to 20 instructions from 36 initially, with only 2 umull instructions instead of 3, and slightly smaller stack footprint. Signed-off-by: Nicolas Pitre <[email protected]>
No description provided.