-
Notifications
You must be signed in to change notification settings - Fork 730
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
[dv,sw] C messaging flow: part 1 (C side) #259
Conversation
@sriyerg One thing I'm not too clear on, what happens when the SW side writes more than 15 arguments? It doesn't seem like compile would fail, so would we just get a weird 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.
Thanks for working on this @sriyerg!
I added some comments wrt build dependency management. I'd like to keep the libraries target independent as much as possible.
I will try this out on an FPGA next.
sw/lib/mprintf.h
Outdated
#define CONCAT2(a, b) CONCAT1(a, b) | ||
|
||
// if DV_SIM, then use DV_MPRINTF macro, else call mprintf() function | ||
#ifdef DV_SIM |
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 DV_SIM, then probably better to not include this file, and use this file as the C interface for FPGA/Verilator/Silicon?
The build system should be able to select dependencies based on target.
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 understand what needs to change - thanks (wanted a quick proof-of-concept PR out for review).
sw/lib/uart.c
Outdated
@@ -73,3 +74,12 @@ int uart_rcv_char(char *c) { | |||
*c = REG32(UART_RDATA(0)); | |||
return 0; | |||
} | |||
|
|||
#ifndef DV_SIM | |||
void uart_mprintf(int sev, const char *fmt, ...) { |
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.
Move uart_mprintf
to mprintf.{h,c} and have mprintf.c include uart.h
that way this will only get compiled by dependencies relying on mprintf.o.
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.
Reworked the implementation - move the msg printing to sw/util and added target specific headers that are selectively picked up. PTAL, thanks!
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.
Thanks for working on this @sriyerg!
I added some comments wrt build dependency management. I'd like to keep the libraries target independent as much as possible.
I will try this out on an FPGA next.
I have reworked the placement of the sources based on our DIF discussions on how we should be laying out the sources. PTAL - i think this aligns well with what we had initially decided.
sw/lib/mprintf.c
Outdated
|
||
#include "mprintf.h" | ||
|
||
#ifndef DV_SIM |
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 is something better handled at the build system dependency level.
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, PTAL.
sw/exts/common/link.ld
Outdated
@@ -6,13 +6,34 @@ GROUP( -lc -lgloss -lgcc -lsupc++ ) | |||
SEARCH_DIR(.) | |||
__DYNAMIC = 0; | |||
|
|||
#ifdef DV_SIM |
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.
Linker scripts traditionally do not support macros in them, but they are a valid input for the preprocessor util (cpp). What I am doing here is passing it through cpp and generating the output, which is devoid of any ifdefs. Linking stage uses the cpp output. see sw/rules.mk lines 29 and 51.
The only thing added as ifdef is the message section. Beside that there is no other modification. I'd prefer not creating target specific linker file since it creates a maintenance overhead (any updates to the 'original' would have to be replicated to target specific linker scripts as well).
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.
ah o i see that makes sense.
That's okay with me, but I think it's probably best if the sw experts weigh in. I have seen in cases like this another link file is INCLUDED. So I'm just not sure what the preferred method is.
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 am ok either way. We can start with preprocessor and switch to some other autogen script if things get too complex.
@gkelly to provide recommendation also.
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 will prefer removing the #ifdef DV_SIM altogether. The existence of this fake mem makes 0 difference to the final image (since the msg_data section is removed altogether when the elf is converted to bin). Only difference is in DV sims, msg prints will result in strings written to the msg_data section during compile time, whereas in FPGA/Verilator/real FW builds, the msg_data section will remain empty. Will leave the decision to you though.
this looks pretty good to me. Thanks Sri for doing this! This is quite cool and I am looking forward to using it :) |
approve from my end, would recommend waiting for a few others to chime in. |
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.
Thanks @sriyerg!
I added some comments for re coding style guide, and some other comments re use of FPGA target, and verbosity of header info.
sw/boot_rom/rom_link.ld
Outdated
} | ||
|
||
/* Memory Allocation */ | ||
_heap_size = 0xe000; | ||
_stack_size = 0x2000; | ||
_stack_start = ORIGIN(ram) + _heap_size + _stack_size; | ||
/* Reserving upper 32 bytes of ram for DV */ | ||
_stack_start = ORIGIN(ram) + _heap_size + _stack_size - 0x20; |
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.
Can you make the - 0x20
portion configurable by DV_SIM?
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.
sw/exts/common/link.ld
Outdated
@@ -6,13 +6,34 @@ GROUP( -lc -lgloss -lgcc -lsupc++ ) | |||
SEARCH_DIR(.) | |||
__DYNAMIC = 0; | |||
|
|||
#ifdef DV_SIM |
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 am ok either way. We can start with preprocessor and switch to some other autogen script if things get too complex.
@gkelly to provide recommendation also.
sw/util/fpga/msg_print.h
Outdated
|
||
// use predefined macros in ../msg.h with standard header (recommended) | ||
#define MSG_HEADER(msg_type, verbosity) \ | ||
msg_type verbosity ": (" __FILE__ ":" _xstr(__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.
I'd probably put the file info behind a verbose compile logging flag.
#if defined(MSG_VERBOSE_HEADER)
#define MSG_HEADER(msg_type, verbosity) msg_type verbosity ": (" __FILE__ ":" _xstr(__LINE__) ")"
#else
#define MSG_HEADER(msg_type, verbosity) msg_type verbosity ": "
#endif
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.
Added MSG_HEADER_INCL_FILE_FILE
to make it more precise and meaningful.
@@ -11,6 +11,7 @@ | |||
## SW_SRCS to be built for that SW test. ## | |||
## SW_NAME: This is the name of the SW test begin run. Optional if SW_DIR name (last dir) is ## | |||
## the same as the SW test name. ## | |||
## TARGET: Target for which the sw is cross-compiled - dv|fpga ## |
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.
Can you add verilator too? Or rename fpga as something more generic, e.g. hw
? Any inputs here from others?
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.
hw
is way too generic (dv sim pertains to hw too). Plus, our directory structure might get confusing (hw/
, sw/
, sw/util/hw
, etc). Typical for asic design development is simulation (dv) and emulation (fpga). Emmulation efforts are used for testing full SW builds. I dont see Verilator as an independent platform having unique set of requirements from a SW build perspective (correct me if I am wrong). We could perhaps build SW for sim or emu efforts (ensure both modes work with Verilator based efforts) and use either 'mode' for Verilator based testing?
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.
Naming things is always hard so I get that there's no ideal answer here, but "hw" does sound like a better name for me. fpga/ASIC/verilator should look the same to software (assuming we're targeting the same version of the IP...) and so a generic "hw" term makes sense to my mind.
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.
In dv, we are indeed simulating the hw. So from my perspective, the dichotomy is more towards "simulation" and "production" SW build. Regardless, the targets for "simulation" will continue to be "dv", "fpga" and "verilator" and each will possibly have a different set of requirements.
From the msg flow perspective, there are currently 2 approaches - print via uart (used by simulation/fpga, simulation/verilator and production) and print via 'elf' flow (used by simulation/dv, and can be potentially used by simulation/verilator as well).
Rather than tying the msging flow to DV, I made it as an independent setting in the Makefile called MSG_FLOW, which is set to uart by default. Setting TARGET=dv will switch MSG_FLOW to elf. I also made associated changes to the linker scripts.
How we should organize the TARGETs and what should be called what is discussion we need to have. I will prefer that discussion to not block the submission of this PR. Please let me know if this works for the time being.
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 agree with Sri. There are probably going to be more cases down the line, where due to sheer design size, the FPGA will either not have some components or have different clock speeds from verilator. It seems good to de-couple those from specific features (like the MSG_FLOW).
sw/util/fpga/msg_print.h
Outdated
// Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#ifndef _MSG_PRINT_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.
It would be nice if these files were in a more generic location. fpga, verilator and silicon will most likely consume this header.
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.
@moidx
Sri and I talked about this and actually explicitly split these out to a sw/util directory, with the intent of these being non-target related. What do you think?
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.
So, you are saying to move the code inside sw/util/fpga
to sw/util
?
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.
o oops sorry. So i think msg_print.h
is meant to be the target specific utilities. There's a different one for dv / fpga, but they dont really relate to hardware, so we decided to stick them in util.
msg.h
is the more general one and is placed in sw/util i think.
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.
Yep, this comment is more about the fact that util/fpga
is used for fpga, verilator and silicon targets. I am not sure if util/hw
would work better? In this case we'd have util/dv
and util/hw
. uti/hw/msg_print.h
uses uart.h
which is hw, so kind of makes sense?
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.
Just a quick note on this - I created an PR #292 for the SV side (which monitors writes to SW_MSG_ADDR and prints the msg to the sim log file). The SV msg monitor is written as a pure Verilog module so it should technically work for Verilator sim as well. Lets talk more tomorrow and decide how to solve this. My thought is, we should use the ELF file based 'backdoor' msg print flow for DV AND Verilator runs and use the UART method for FPGA runs.
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 prefer Verilator to just be left as is since it will give us better system test coverage.
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 maybe we can ping Philipp / Pirmin on this one. We are not really big users of verilator anyways, so it'd be good to get their opinion and how they think this plays out.
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.
we = design / dv on our end.
sw/util/fpga/msg_print.h
Outdated
|
||
// print msgs with custom header (this will break DV flow!) | ||
#define MSG_PRINT(msg_header, fmt, ...) \ | ||
msg_print(uart_send_char, msg_header, fmt VA_ARGS(__VA_ARGS__)); |
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.
Since you are using uart_send_char
, can you include the #include "uart.h"
header? This will help us better keep track of dependencies.
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.
|
||
#include <stdarg.h> | ||
|
||
static void _print_dec(void (*output)(char), unsigned int d) { |
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: can you name this _print_digit
or _print_ascii_num
? print_dec
is a little confusing.
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 vote for _print_digit
, that does sound pretty good
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.
} break; | ||
case 'x': | ||
case 'X': { | ||
unsigned int n = va_arg(va, unsigned int); |
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.
'X'
should be upper case hex. I think we want to stick to conventional string formats since this is going to be referenced in many places.
char c = va_arg(va, int); | ||
output(c); | ||
} break; | ||
case 'h': { // little endian hex dump |
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.
Same comment as above h
and H
are not standard. We should add print buffer functions 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.
@moidx
do you think we should just reference some open source version of print?
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 am ok with just making this version more standard.
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 will prefer submitting this PR and making any further changes needed as a part of next PR if you are okay with it (can file issues if needed).
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.
Sorry if I missed the earlier discussion, but is it necessary to have all the preprocessor magic vs just having a normal function with va_start/va_arg etc?
@@ -11,6 +11,7 @@ | |||
## SW_SRCS to be built for that SW test. ## | |||
## SW_NAME: This is the name of the SW test begin run. Optional if SW_DIR name (last dir) is ## | |||
## the same as the SW test name. ## | |||
## TARGET: Target for which the sw is cross-compiled - dv|fpga ## |
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.
Naming things is always hard so I get that there's no ideal answer here, but "hw" does sound like a better name for me. fpga/ASIC/verilator should look the same to software (assuming we're targeting the same version of the IP...) and so a generic "hw" term makes sense to my mind.
sw/util/dv/msg_print.h
Outdated
#define _WR_VA_ARG_N(...) \ | ||
_WR_VA_ARG_(CONCAT2(_WR_VA_ARG, VA_NARGS(__VA_ARGS__)), __VA_ARGS__) | ||
|
||
// print msgs with a cusotm header |
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.
custom
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.
Do you think the SW pieces build for FPGA / Verilator / final silicon should be identical? @asb / @moidx
I am not in favor of hw
(we are after all, verifying hw
in DV as well). To me, this sounds like a dichotomy between 'simulation' and 'production' software builds, the former being used in DV and the latter being used in FPGA/Verilator/silicon.
If yes, then to me, the following makes more sense -
SW_BUILD_MODE=sim|prod
OR
SW_BUILD_MODE=dv_sim|prod
SW_BUILD_MODE=sim (or dv_sim) will exclusively be used by DV efforts (I would argue that Verilator falls into this as well and the DV msg flow will work for Verilator as well, but upto the Verilator users to decide).
I would assume that to not be the case - I think FPGA/Verilator/DV/Silicon will have different requirements, so we should perhaps continue with TARGET=dv|verilator|fpga|silicon.
As for msging flow, I can use something else for differentiation instead of TARGET (perhaps MSG_FLOW=elf|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.
would it be easier if we planned for a quick sync between all of us?
I agree with Sri that keeping SW pieces identical for FPGA / silicon / verilator will probably be a tall order in the long run. If nothing else they'll likely vary in clock speeds and perhaps how some of the more 'analog' modules are modeled.
I also think the idea of making specific functions features that each TARGET can select seems a lot more flexible.
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 am also in favor of handling configuration options at the feature level, since it seems to yield the most flexible build implementation. Expanding the previous example:
TARGET=dv
ifeq ($(TARGET), "dv")
MSG_FLOW = "elf"
else ifeq ($(TARGET), "fpga")
MSG_FLOW = "uart"
endif
Hi Sri - we've been discussing this a bit at lowRISC. We're finding it pretty hard to review without a high level summary of the goals, requirements etc. Would you be able to write up a brief rationale / design doc? |
sure, will do. |
_flash_start = 0x20000000; | ||
_flash_end = _flash_start + _flash_size; | ||
|
||
#if MSG_FLOW == elf |
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.
replaced DV_SIM with MSG_FLOW flag. this can be turned on independently for any target (dv/verilator/verifying full production fw stack in dv, etc).
- Added generic sw/util/msg.{c, h} with variadic function to print formatted string via real hardware - Added standard implementation-independent msg print macros in msg.h (MSG_INFO, MSG_ERROR etc) - These standard msg print macros rely on additional macros defined in implementation/flow-specific macros defined in sw/util/msg_<flow>/msg_print.h - by default, 'uart' flow is selected, so the msgs are printed char by char via UART using the generic function defined in msg.c - for DV (or simulation really), added MSG_FLOW=elf where sw/util/msg_elf/msg_print.h header is picked, which converts msg prints to writes to pre-determined addr in ram - Updated linker scripts to reserve upper 32bytes of ram for C<->SV messaging
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.
Pending for feedback from design review before proceeding. Thanks
My concerns with this change are that it adds an API that's hard to satisfy, and one that isn't very 'familiar', by which I mean it's not a libc interface and doesn't consume a libc interface. If we want to take any of the code written against this API and and run it under a different harness (or an OS) then we'll need to merge this code there or replicate the macro-based API. It's also fairly opinionated in the logging prefixes and levels. This isn't necessarily a bad thing, but the way this is layered seems like it's very tightly coupled. How does this sound: split this into a libc-like layer (puts, printf, etc) and a 'msg' layer that does the logging verbosity, prefix, etc. If we add a little bit of logic to the puts/printf layer that tests if the format string (or written string) is in the NOLOAD section then we can use your bypass to print it out. Otherwise, it behaves normally. In my eyes this has two benefits: separation of the concerns of logging decoration and actual IO, and switching to a libc API that's familiar enough that we can use or reproduce it reliably later. Thoughts? |
flash (rx) : ORIGIN = _flash_start, LENGTH = _flash_end | ||
#if MSG_FLOW == elf | ||
/* Fake memory for extracting messages from print strings from elf */ | ||
msg_mem(!r!w!x) : ORIGIN = _msg_mem_start, LENGTH = _msg_mem_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.
Does this need to have a MEMORY section, or can it just be marked (NOLOAD)
?
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 can be. I will give it a try.
@@ -101,6 +139,12 @@ SECTIONS | |||
{ | |||
[ .stabstr ] | |||
} | |||
|
|||
#if MSG_FLOW == elf | |||
.msg_data _msg_mem_start : { |
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 this can be made (NOLOAD)
and then it doesn't need to be stripped with objcopy later.
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.
My concerns with this change are that it adds an API that's hard to satisfy, and one that isn't very 'familiar', by which I mean it's not a libc interface and doesn't consume a libc interface. If we want to take any of the code written against this API and and run it under a different harness (or an OS) then we'll need to merge this code there or replicate the macro-based API.
It's also fairly opinionated in the logging prefixes and levels. This isn't necessarily a bad thing, but the way this is layered seems like it's very tightly coupled.
How does this sound: split this into a libc-like layer (puts, printf, etc) and a 'msg' layer that does the logging verbosity, prefix, etc. If we add a little bit of logic to the puts/printf layer that tests if the format string (or written string) is in the NOLOAD section then we can use your bypass to print it out. Otherwise, it behaves normally.
In my eyes this has two benefits: separation of the concerns of logging decoration and actual IO, and switching to a libc API that's familiar enough that we can use or reproduce it reliably later.
Thoughts?
The msg print APIs (MSG_INFO*, MSG_WARNING, MSG_ERROR and MSG_FATAL) which is what is exposed, do have a printf-like interface. I am not sure I understand what's different about those that's making them incompatible with libc.
The logging, prefixes, header construction etc does form the 'msg' layer and is fully customizable based on the target specific requirements (you could define all of those to be empty strings if they are deemed unnecessary) and are intended to happen behind-the-scenes when these APIs are invoked. These macros finally invoke the MSG_PRINT() macro which is intended to be implementation-specific. It can very well be defined to call libc-like functions underneath.
In a way, there is already a separation between msg layer and the libc layer. Only difference being the msg layer (macro APIs) is what is being exposed for use and the libc layer being called underneath. If we go the other way around, I am not sure how we can support other things. For DV, the environment is very resource constrained (when simulating the whole chip in RTL cycle by cycle, every bit of processing on the CPU adds significant about of test run time (which is of no value to the actual test). The macro based solution gives us the fastest possible implementation in terms of sim run time.
Re. your point about plucking this code out and running it on a different harness - is your thought process to cherry-pick individual sources from the shared lib code rather than the whole thing (I would expect you would rather want to build the whole library together as one piece, which will include the APIs as well).
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.
My concerns with this change are that it adds an API that's hard to satisfy, and one that isn't very 'familiar', by which I mean it's not a libc interface and doesn't consume a libc interface. If we want to take any of the code written against this API and and run it under a different harness (or an OS) then we'll need to merge this code there or replicate the macro-based API.
It's also fairly opinionated in the logging prefixes and levels. This isn't necessarily a bad thing, but the way this is layered seems like it's very tightly coupled.
How does this sound: split this into a libc-like layer (puts, printf, etc) and a 'msg' layer that does the logging verbosity, prefix, etc. If we add a little bit of logic to the puts/printf layer that tests if the format string (or written string) is in the NOLOAD section then we can use your bypass to print it out. Otherwise, it behaves normally.
In my eyes this has two benefits: separation of the concerns of logging decoration and actual IO, and switching to a libc API that's familiar enough that we can use or reproduce it reliably later.
Thoughts?The msg print APIs (MSG_INFO*, MSG_WARNING, MSG_ERROR and MSG_FATAL) which is what is exposed, do have a printf-like interface. I am not sure I understand what's different about those that's making them incompatible with libc.
You're right, I misunderstood how this API was supposed to work. This could absolutely be layered on top of a libc using the _impl.h
approach.
The logging, prefixes, header construction etc does form the 'msg' layer and is fully customizable based on the target specific requirements (you could define all of those to be empty strings if they are deemed unnecessary) and are intended to happen behind-the-scenes when these APIs are invoked. These macros finally invoke the MSG_PRINT() macro which is intended to be implementation-specific. It can very well be defined to call libc-like functions underneath.
In a way, there is already a separation between msg layer and the libc layer. Only difference being the msg layer (macro APIs) is what is being exposed for use and the libc layer being called underneath. If we go the other way around, I am not sure how we can support other things. For DV, the environment is very resource constrained (when simulating the whole chip in RTL cycle by cycle, every bit of processing on the CPU adds significant about of test run time (which is of no value to the actual test). The macro based solution gives us the fastest possible implementation in terms of sim run time.
Re. your point about plucking this code out and running it on a different harness - is your thought process to cherry-pick individual sources from the shared lib code rather than the whole thing (I would expect you would rather want to build the whole library together as one piece, which will include the APIs as well).
Yes, we would probably want to build the entire library together and provide our own _impl.h
.
@gkelly Also, if there's a libc like layer, I'm guessing that means everyone would call printf directly? Wouldn't that function call lose some of the information Sri wants to keep? For example line number and file since it's not typically passed through a printf function call? I might be thinking in completely the wrong direction, feel free to correct me. |
Hi Sri, @imphil and I just sat down to work through the (based on your high-level overview doc - thanks for that). We now have a much clearer idea of what you're trying to achieve and why. The ELF hacking isn't pretty, but does seem the sensible way of achieving the goal of avoiding writing out format string contents. Feedback:
|
Thank you for your comments - I have made PR #357 which splits this PR into first of 2 parts - 'regular' print msg via UART. I have clearly documented the generic set of APIs that can be made implementation specific. I hope that is easier to review. I will update the proposal doc tomorrow. |
The last callee before argument formatting would need to check the format string to see where it is in memory. If it's in
No, I think you're right and I was misunderstanding the intent of the change and the |
- provide a generic set of APIs to print msgs - provide ability to attach severity (msg type) and verbosity to msgs - provide ability to attach a header to the msg underneath - privide ability to construct the header based on severity, verbosity file and line number for ease of debug - provide a generic msg_print() function that can parse a formatted string and take variable number of args - provide implementation specific APIs in sw/util/msg_uart/msg_api_impl.h to do the prints via UART - PR lowRISC#259 is being split to make the review easier - this PR focuses on providing a high level API and 'typical' SW implementation of it using UART, - Subsequent PR will focus on DV specific implementation Signed-off-by: Srikrishna Iyer <sriyer@google.com>
- provide a generic set of APIs to print msgs - provide ability to attach severity (msg type) and verbosity to msgs - provide ability to attach a header to the msg underneath - privide ability to construct the header based on severity, verbosity file and line number for ease of debug - provide a generic msg_print() function that can parse a formatted string and take variable number of args - provide implementation specific APIs in sw/util/msg_uart/msg_api_impl.h to do the prints via UART - PR #259 is being split to make the review easier - this PR focuses on providing a high level API and 'typical' SW implementation of it using UART, - Subsequent PR will focus on DV specific implementation Signed-off-by: Srikrishna Iyer <sriyer@google.com>
string to UART
based printing and DV printing
messaging
TODOs:
(next PR)
What's in part 2:
messages into data sructures that SV can lookup