Skip to content

Commit 079cc94

Browse files
mikeydpgeorge
authored andcommitted
powerpc: Add initial port to bare metal PowerPC arch.
Runs in microwatt (GHDL and FPGA) and qemu. Port done initially by Michael Neuling, with help from Anton Blanchard and Jordan Niethe.
1 parent 19ca025 commit 079cc94

20 files changed

+1087
-0
lines changed

Diff for: .travis.yml

+9
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,12 @@ jobs:
232232
- sudo apt-get install libnewlib-arm-none-eabi
233233
script:
234234
- make ${MAKEOPTS} -C ports/teensy
235+
236+
# powerpc port
237+
- stage: test
238+
env: NAME="powerpc port build"
239+
install:
240+
- sudo apt-get install gcc-powerpc64le-linux-gnu
241+
- sudo apt-get install libc6-dev-ppc64el-cross
242+
script:
243+
- make ${MAKEOPTS} -C ports/powerpc CROSS_COMPILE=powerpc64le-linux-gnu-

Diff for: ports/powerpc/Makefile

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
include ../../py/mkenv.mk
2+
3+
# qstr definitions (must come before including py.mk)
4+
QSTR_DEFS = qstrdefsport.h
5+
6+
# include py core make definitions
7+
include $(TOP)/py/py.mk
8+
9+
ARCH = $(shell uname -m)
10+
ifneq ("$(ARCH)", "ppc64")
11+
ifneq ("$(ARCH)", "ppc64le")
12+
CROSS_COMPILE = powerpc64le-linux-
13+
endif
14+
endif
15+
16+
INC += -I.
17+
INC += -I$(TOP)
18+
INC += -I$(BUILD)
19+
20+
CFLAGS = $(INC) -g -Wall -std=c99 $(COPT)
21+
CFLAGS += -mno-string -mno-multiple -mno-vsx -mno-altivec -nostdlib
22+
CFLAGS += -mlittle-endian -mstrict-align -msoft-float
23+
CFLAGS += -Os
24+
CFLAGS += -fdata-sections -ffunction-sections -fno-stack-protector -ffreestanding
25+
CFLAGS += -U_FORTIFY_SOURCE
26+
27+
LDFLAGS = -N -T powerpc.lds -nostdlib
28+
29+
LIBS =
30+
31+
SRC_C = \
32+
main.c \
33+
uart_core.c \
34+
uart_potato.c \
35+
uart_lpc_serial.c \
36+
lib/utils/printf.c \
37+
lib/utils/stdout_helpers.c \
38+
lib/utils/pyexec.c \
39+
lib/libc/string0.c \
40+
lib/mp-readline/readline.c \
41+
$(BUILD)/_frozen_mpy.c \
42+
43+
OBJ = $(PY_CORE_O)
44+
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
45+
OBJ += $(BUILD)/head.o
46+
47+
all: $(BUILD)/firmware.elf $(BUILD)/firmware.map $(BUILD)/firmware.bin
48+
49+
$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h
50+
$(ECHO) "MISC freezing bytecode"
51+
$(Q)$(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=mpz $< > $@
52+
53+
$(BUILD)/firmware.elf: $(OBJ) powerpc.lds
54+
$(ECHO) "LINK $@"
55+
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
56+
$(Q)$(SIZE) $@
57+
58+
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
59+
$(Q)$(OBJCOPY) -O binary $^ $(BUILD)/firmware.bin
60+
61+
$(BUILD)/firmware.map: $(BUILD)/firmware.elf
62+
$(Q)nm $^ | sort > $(BUILD)/firmware.map
63+
64+
include $(TOP)/py/mkrules.mk

Diff for: ports/powerpc/README.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# The PowerPC port that runs on microwatt and qemu
2+
3+
This port is intended to be a minimal MicroPython port that runs in
4+
QEMU, microwatt simulator with ghdl or microwatt on Xilinx FPGA with
5+
potato UART.
6+
7+
## Building
8+
9+
By default the port will be built for the host machine:
10+
11+
$ make
12+
13+
## Cross compilation for POWERPC
14+
15+
If you need to cross compilers you'll want to grab a powerpc64le
16+
compiler (not powerpc or powerpc64).
17+
18+
On Ubuntu (18.04) you'll want:
19+
20+
$ apt install gcc-powerpc64le-linux-gnu
21+
22+
*(Use CROSS_COMPILE=powerpc64le-linux-gnu-)*
23+
24+
If your distro doesn't have cross compilers, you can get cross compilers here:
25+
- https://toolchains.bootlin.com/
26+
*(use CROSS_COMPILE=powerpc64le-buildroot-linux-gnu-)*
27+
28+
(Avoid musl libc as it defines __assert_fail() differently to glibc
29+
which breaks the micropython powerpc code)
30+
31+
Then do:
32+
33+
$ make CROSS_COMPILE=<compiler prefix>
34+
35+
Building will produce the build/firmware.bin file which can be used
36+
QEMU or [microwatt](https://github.com/antonblanchard/microwatt).
37+
38+
To run in QEMU use:
39+
40+
$ ./qemu-system-ppc64 -M powernv -cpu POWER9 -nographic -bios build/firmware.bin

Diff for: ports/powerpc/frozentest.mpy

196 Bytes
Binary file not shown.

Diff for: ports/powerpc/frozentest.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
print('uPy')
2+
print('a long string that is not interned')
3+
print('a string that has unicode αβγ chars')
4+
print(b'bytes 1234\x01')
5+
print(123456789)
6+
for i in range(4):
7+
print(i)

Diff for: ports/powerpc/head.S

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019, Michael Neuling, IBM Corporation.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#define STACK_TOP 0x60000
28+
29+
#define FIXUP_ENDIAN \
30+
tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \
31+
b 191f; /* Skip trampoline if endian is good */ \
32+
.long 0xa600607d; /* mfmsr r11 */ \
33+
.long 0x01006b69; /* xori r11,r11,1 */ \
34+
.long 0x05009f42; /* bcl 20,31,$+4 */ \
35+
.long 0xa602487d; /* mflr r10 */ \
36+
.long 0x14004a39; /* addi r10,r10,20 */ \
37+
.long 0xa64b5a7d; /* mthsrr0 r10 */ \
38+
.long 0xa64b7b7d; /* mthsrr1 r11 */ \
39+
.long 0x2402004c; /* hrfid */ \
40+
191:
41+
42+
/* Load an immediate 64-bit value into a register */
43+
#define LOAD_IMM64(r, e) \
44+
lis r,(e)@highest; \
45+
ori r,r,(e)@higher; \
46+
rldicr r,r, 32, 31; \
47+
oris r,r, (e)@h; \
48+
ori r,r, (e)@l;
49+
50+
.section ".head","ax"
51+
52+
/*
53+
* Microwatt comes in at 0 as little endian so we do not need to worry up
54+
* FIXUP_ENDIAN.
55+
*/
56+
. = 0
57+
.global _start
58+
_start:
59+
b boot_entry
60+
61+
/* QEMU comes in at 0x10. Put a value in argc/r3 to distingush from
62+
* microwatt. */
63+
. = 0x10
64+
FIXUP_ENDIAN
65+
LOAD_IMM64(%r3, 1)
66+
b boot_entry
67+
68+
.global boot_entry
69+
boot_entry:
70+
/* Save R3 to non-volatile register */
71+
mr %r14, %r3
72+
restart:
73+
/*
74+
* setup stack with a safety gap, since we might write to the
75+
* previous frame.
76+
*/
77+
LOAD_IMM64(%r1, STACK_TOP - 0x100)
78+
LOAD_IMM64(%r12, main)
79+
mtctr %r12
80+
bctrl
81+
82+
/* On exit, restart */
83+
mr %r3, %r14
84+
b restart
85+
86+
#define EXCEPTION(nr) \
87+
.= nr; \
88+
b .
89+
90+
/* More exception stubs */
91+
EXCEPTION(0x300)
92+
EXCEPTION(0x380)
93+
EXCEPTION(0x400)
94+
EXCEPTION(0x480)
95+
EXCEPTION(0x500)
96+
EXCEPTION(0x600)
97+
EXCEPTION(0x700)
98+
EXCEPTION(0x800)
99+
EXCEPTION(0x900)
100+
EXCEPTION(0x980)
101+
EXCEPTION(0xa00)
102+
EXCEPTION(0xb00)
103+
EXCEPTION(0xc00)
104+
EXCEPTION(0xd00)
105+
EXCEPTION(0xe00)
106+
EXCEPTION(0xe20)
107+
EXCEPTION(0xe40)
108+
EXCEPTION(0xe60)
109+
EXCEPTION(0xe80)
110+
EXCEPTION(0xf00)
111+
EXCEPTION(0xf20)
112+
EXCEPTION(0xf40)
113+
EXCEPTION(0xf60)
114+
EXCEPTION(0xf80)
115+
EXCEPTION(0x1000)
116+
EXCEPTION(0x1100)
117+
EXCEPTION(0x1200)
118+
EXCEPTION(0x1300)
119+
EXCEPTION(0x1400)
120+
EXCEPTION(0x1500)
121+
EXCEPTION(0x1600)

Diff for: ports/powerpc/main.c

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019, Michael Neuling, IBM Corporation.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <stdio.h>
28+
29+
#include "py/compile.h"
30+
#include "py/runtime.h"
31+
#include "py/repl.h"
32+
#include "py/gc.h"
33+
#include "py/mperrno.h"
34+
#include "py/stackctrl.h"
35+
#include "lib/utils/pyexec.h"
36+
37+
void __stack_chk_fail(void);
38+
void __stack_chk_fail(void) {
39+
static bool failed_once;
40+
41+
if (failed_once) {
42+
return;
43+
}
44+
failed_once = true;
45+
printf("Stack corruption detected !\n");
46+
assert(0);
47+
}
48+
49+
/* fill in __assert_fail for libc */
50+
void __assert_fail(const char *__assertion, const char *__file,
51+
unsigned int __line, const char *__function) {
52+
printf("Assert at %s:%d:%s() \"%s\" failed\n", __file, __line, __function, __assertion);
53+
for (;;) ;
54+
}
55+
56+
static char *stack_top;
57+
#if MICROPY_ENABLE_GC
58+
static char heap[32 * 1024];
59+
#endif
60+
61+
extern void uart_init_ppc(int qemu);
62+
63+
int main(int argc, char **argv) {
64+
int stack_dummy;
65+
stack_top = (char*)&stack_dummy;
66+
67+
// microwatt has argc/r3 = 0 whereas QEMU has r3 set in head.S
68+
uart_init_ppc(argc);
69+
70+
#if MICROPY_ENABLE_PYSTACK
71+
static mp_obj_t pystack[1024];
72+
mp_pystack_init(pystack, &pystack[1024]);
73+
#endif
74+
75+
#if MICROPY_STACK_CHECK
76+
mp_stack_ctrl_init();
77+
mp_stack_set_limit(48 * 1024);
78+
#endif
79+
80+
#if MICROPY_ENABLE_GC
81+
gc_init(heap, heap + sizeof(heap));
82+
#endif
83+
mp_init();
84+
#if MICROPY_ENABLE_COMPILER
85+
#if MICROPY_REPL_EVENT_DRIVEN
86+
pyexec_event_repl_init();
87+
for (;;) {
88+
int c = mp_hal_stdin_rx_chr();
89+
if (pyexec_event_repl_process_char(c)) {
90+
break;
91+
}
92+
}
93+
#else
94+
pyexec_friendly_repl();
95+
#endif
96+
#else
97+
pyexec_frozen_module("frozentest.py");
98+
#endif
99+
mp_deinit();
100+
return 0;
101+
}
102+
103+
void gc_collect(void) {
104+
// WARNING: This gc_collect implementation doesn't try to get root
105+
// pointers from CPU registers, and thus may function incorrectly.
106+
void *dummy;
107+
gc_collect_start();
108+
gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
109+
gc_collect_end();
110+
gc_dump_info();
111+
}
112+
113+
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
114+
mp_raise_OSError(MP_ENOENT);
115+
}
116+
117+
mp_import_stat_t mp_import_stat(const char *path) {
118+
return MP_IMPORT_STAT_NO_EXIST;
119+
}
120+
121+
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
122+
return mp_const_none;
123+
}
124+
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
125+
126+
void nlr_jump_fail(void *val) {
127+
while (1);
128+
}
129+
130+
void NORETURN __fatal_error(const char *msg) {
131+
while (1);
132+
}
133+
134+
#ifndef NDEBUG
135+
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
136+
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
137+
__fatal_error("Assertion failed");
138+
}
139+
#endif

0 commit comments

Comments
 (0)