Skip to content

Initial port to powerpc bare metal #5093

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

Closed
wants to merge 1 commit into from

Conversation

mikey
Copy link
Contributor

@mikey mikey commented Sep 11, 2019

This runs in qemu using:

$ ./qemu-system-ppc64 -M powernv -cpu POWER9 -nographic -bios build/firmware.bin

It can also run in microwatt (new POWER softcore) using GHDL or on an FGPA. Instructions on how to run in GHDL are here:
https://github.com/antonblanchard/microwatt/blob/master/README.md

Thanks to Anton Blanchard and Jordan Niethe for helping with this port.

@dpgeorge
Copy link
Member

Thanks for the contribution. It's nice that it's a minimal port to start with, makes it easier to review!

I guess MicroPython already runs on PowerPC via the unix port, and here is a real bare-metal port. I'm just wonder though if this scales to eventually add bare-metal ports to other archs like x86, or if these could all be merged into one "bare-cpu" port. It depends how much they'd have in common (probably not that much) and whether peripherals will be supported or not. Are there plans to add peripheral support (eg GPIO, SPI) to this port?

What is the reason to add the skiboot code? Seems like this should be provided by the toolchain?

@mikey
Copy link
Contributor Author

mikey commented Sep 16, 2019

Thanks for the contribution. It's nice that it's a minimal port to start with, makes it easier to review!

Thanks!

I guess MicroPython already runs on PowerPC via the unix port, and here is a real bare-metal port. I'm just wonder though if this scales to eventually add bare-metal ports to other archs like x86, or if these could all be merged into one "bare-cpu" port. It depends how much they'd have in common (probably not that much) and whether peripherals will be supported or not.

The core of the port is mostly architecture specific. head.S, the nlr code, the uart, the linker script would all need to change for a different arch like x86. So I think the core code reuse would be minimal.

Are there plans to add peripheral support (eg GPIO, SPI) to this port?

I'd like to but at this stage we are concentrating on microwatt which doesn't have any I/O as yet (other than the UART). The qemu port was just to make it easier to test (for you and me).

FWIW There is some info on microwatt and micropython here https://lwn.net/Articles/796796/ (see "Demo time") and https://www.youtube.com/watch?v=JdMTLs7EMM0

What is the reason to add the skiboot code? Seems like this should be provided by the toolchain?

The skiboot code was there to get going quicker and with a toolchain that doesn't have the libc libraries compiled in (which makes building cross toolchains easier). I could try to get rid of them if they are a problem.

@dpgeorge
Copy link
Member

The skiboot code was there to get going quicker and with a toolchain that doesn't have the libc libraries compiled in (which makes building cross toolchains easier). I could try to get rid of them if they are a problem.

I only took a brief look and the main thing that stood out was licensing/copyright of these files being different from core MicroPython. We try to consolidate such files to lib/ (eg in a submodule) if they are really necessary.

For general points related to new ports, see also this comment: #4557 (comment)

@mikey mikey force-pushed the powerpc-upstream branch 2 times, most recently from d1c7f57 to ddfbf48 Compare October 1, 2019 11:28
@mikey
Copy link
Contributor Author

mikey commented Oct 1, 2019

(sorry for the slow update)

I only took a brief look and the main thing that stood out was licensing/copyright of these files being different from core MicroPython. We try to consolidate such files to lib/ (eg in a submodule) if they are really necessary.

I've updated the code to remove these using more compiler builtins now.

All new files are MIT licensed.

For general points related to new ports, see also this comment: #4557 (comment)

  1. are the chips widely available to the public and will they be for the foreseeable future?

You can either use qemu or the microwatt softcore from https://github.com/antonblanchard/microwatt

I've added instructions on how to use qemu in ports/powerpc/README.md

  1. are development boards easily available?

microwatt is a softcore which can be put on numerous FPGA development boards like the Arty A7, Nexys A7, Nexys Video.

  1. is the toolchain open source (or at least free to obtain)?

Yes, we are using GCC.

  1. are there plans to support multiple MCUs/SoCs?

Yes. We support microwatt on various FPGA boards. We'd like to support more IO and soft IP which can be built into SOCs

  1. will there be someone around for the long term to maintain this port?

Yes me! I've been working on Linux on powerpc for 10+ years:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=author&q=neuling

  1. the license (and copyright) must be appropriate.

All MIT (fixed from initial PR).

Other things I've changed this the initial PR:

  1. Added a travis powerpc test
  2. Cleaned up the makefile CFLAGS options
  3. Removed the divide emulation code (since microwatt now support divide instructions)
  4. Rebased on latest master branch (small conflict in nlr.h and updated frozentest.mpy).

Copy link
Contributor

@shenki shenki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I have made some minor comments that are my opinion. If you're unsure then we should defer to the micropython experts.

@dpgeorge, I will also be available to help maintain this port.

#endif
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
//do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT);
#else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this commented out code be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove. This was left over from the ports/minimal copy.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove


/*
* Core UART functions to implement for a port
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment could go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep thanks

* Core UART functions to implement for a port
*/

#if MICROPY_MIN_USE_STM32_MCU
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks unrelated to the ppc port

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, copy and paste from other ports

#define USART1 ((periph_uart_t*)0x40011000)
#endif

static int potato_console;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be clearer if the potato and the qemu uarts go in different files.

Also mention what/where the potato uart is (I think it's some IP that microwatt is using?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.
Yeah potato uart is the uart we use for microwatt. It's from https://github.com/skordal/potato. I'll make that clearer in the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the selection between lpc and potato need to be dynamic, or can it be configured at compile time? (in the latter case there's no need for these variables)

@mikey mikey force-pushed the powerpc-upstream branch from ddfbf48 to 8daea61 Compare October 2, 2019 11:34
@mikey
Copy link
Contributor Author

mikey commented Oct 2, 2019

Updated branch to address @shenki comments.

@dpgeorge
Copy link
Member

I tested this on Arch Linux which only has a powerpc toolchain in the AUR, so instead I tried using powerpc64le-linux-musl-cross (gcc 9.2.1) from https://musl.cc . It compiled except I needed to change the 3rd arg to main.c:__assert_fail from unsigned int to int.

Is it possible to use int here with the Ubuntu toolchain?

It also executed correctly in qemu-system-ppc64 which is great! But I did notice it used 100% CPU at an idle prompt. Is it possible to insert an idle instruction in the UART busy wait loop?

Also, I think it'd be good to put in the README some notes about what toolchain to use and/or where to get it.

Copy link
Member

@dpgeorge dpgeorge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For code style, tabs are not used, instead 4 spaces. And some other things. To make it easy, just run astyle on the files:

$ astyle --options=astyle.fmt *.?

where astyle.fmt contains:

--style=google
--indent=spaces=4
--attach-closing-while
--add-brackets
--indent-switches
--indent-after-parens
--indent-labels
--indent-preproc-define
--indent-preproc-cond
--pad-header
--unpad-paren
--add-braces
--convert-tabs

// Receive single character
int mp_hal_stdin_rx_chr(void) {
unsigned char c = 0;
#if MICROPY_MIN_USE_STDOUT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, removing.

void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
#if MICROPY_MIN_USE_STDOUT
int r = write(1, str, len);
(void)r;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, removing

#define POTATO_CONSOLE_STATUS_RX_FULL 0x04
#define POTATO_CONSOLE_STATUS_TX_FULL 0x08
#define POTATO_CONSOLE_CLOCK_DIV 0x18
#define POTATO_CONSOLE_IRQ_EN 0x20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please line these up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

@dpgeorge dpgeorge added the ports Relates to multiple ports, or a new/proposed port label Oct 10, 2019
@mikey
Copy link
Contributor Author

mikey commented Oct 11, 2019

I tested this on Arch Linux which only has a powerpc toolchain in the AUR, so instead I tried using powerpc64le-linux-musl-cross (gcc 9.2.1) from https://musl.cc . It compiled except I needed to change the 3rd arg to main.c:__assert_fail from unsigned int to int.

Is it possible to use int here with the Ubuntu toolchain?

This is a difference between the definitions of __assert_fail() between glibc and musl. It's a musl issue AFAICT https://www.openwall.com/lists/musl/2019/03/04/6

It also executed correctly in qemu-system-ppc64 which is great! But I did notice it used 100% CPU at an idle prompt. Is it possible to insert an idle instruction in the UART busy wait loop?

Unfortunately without adding support to exceptions, we can't do this bare metal on POWER. It's something we could add in the future.

Also, I think it'd be good to put in the README some notes about what toolchain to use and/or where to get it.

Will do and I'll say to avoid musl for now.

@mikey
Copy link
Contributor Author

mikey commented Oct 11, 2019

Pushed update to address commends from @dpgeorge

  1. Fixed formatting with astyle
  2. Removed some dead code
  3. Update README to say avoid musl based libc and give suggestions on which cross compilers to use
  4. Included link to microwatt

@mikey
Copy link
Contributor Author

mikey commented Oct 16, 2019

Pushed minor fix for whitespace breakage in ports/powerpc/head.S

@mikey mikey force-pushed the powerpc-upstream branch 2 times, most recently from 8ed9525 to bb430f1 Compare October 17, 2019 00:32
@mikey
Copy link
Contributor Author

mikey commented Oct 17, 2019

Repushed to fix the travis failure once merged.

Copy link
Member

@dpgeorge dpgeorge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it with the toolchain from https://toolchains.bootlin.com/ and it works well.

Just a few minor items to address, then it should be good to go in.

INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
INC += -Iskiboot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line can go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, thanks

@@ -0,0 +1,40 @@
# The minimal port
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be something like "The PowerPC port"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

@@ -0,0 +1,40 @@
# The minimal port

This port is intended to be a minimal MicroPython port that runs in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"... MicroPython port to the PowerPC architecture that runs ..."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops thanks :-)

#endif
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
//do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT);
#else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove

KEEP(*(.head))
}

. = 0x1700;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add a comment as to why this number / what this line does?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, it for putting it right after the exception vectors. I'll add the comment in the code

#define USART1 ((periph_uart_t*)0x40011000)
#endif

static int potato_console;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the selection between lpc and potato need to be dynamic, or can it be configured at compile time? (in the latter case there's no need for these variables)

py/nlrpowerpc.c Outdated
:
);

assert(0); /* should never get here */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be replaced with MP_UNREACHABLE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

(github won't let me comment on the console question so commenting here)
The console is dynamically selected (not compile time), so we need those variables.

Runs in microwatt (GHDL and FPGA) + qemu

Port done initially by Michael Neuling, with help from Anton Blanchard
and Jordan Niethe.

Signed-off-by: Michael Neuling <mikey@neuling.org>
@mikey
Copy link
Contributor Author

mikey commented Oct 22, 2019

New push to address comments from @dpgeorge and rebase to latest master

  1. Fixed readme text
  2. Removed do_str code from main.c
  3. documented linker offset
  4. use MP_UNREACHABLE in nlr code rather than assert(0)

@dpgeorge
Copy link
Member

Thank's for updating. Merged in 079cc94 with some fixups to code style, mainly indenting. Also simplified a bit the Makefile because there's already a rule in py/mkrules.mk to build .S files.

Great contribution, thank you!

@dpgeorge dpgeorge closed this Oct 22, 2019
tannewt added a commit to tannewt/circuitpython that referenced this pull request Aug 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ports Relates to multiple ports, or a new/proposed port
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants