1
0
mirror of https://github.com/antonblanchard/chiselwatt.git synced 2026-04-04 21:17:43 +00:00

Merge pull request #33 from carlosedp/add_samples

Add hello_world sample sources and Makefile targets
This commit is contained in:
Anton Blanchard
2020-05-01 19:53:41 +10:00
committed by GitHub
19 changed files with 16918 additions and 16313 deletions

8
.gitignore vendored
View File

@@ -6,6 +6,7 @@ test_run_dir/
*.anno.json
*.fir
*.vcd
.metals
insns.hex
firrtl_black_box_resource_files.f
chiselwatt_out.config
@@ -18,4 +19,9 @@ Core.v
Core.fir
Core.anno.json
LoadStoreInsns.hex
MemoryBlackBoxInsns.hex
MemoryBlackBoxInsns.hex
samples/micropython
samples/hello_world/hello_world.bin
samples/hello_world/hello_world.elf
samples/hello_world/hello_world.o
samples/hello_world/head.o

View File

@@ -115,13 +115,33 @@ chiselwatt.svf: chiselwatt.bit
prog: check-board-vars chiselwatt.svf
$(OPENOCD) -f $(OPENOCD_JTAG_CONFIG) -f $(OPENOCD_DEVICE_CONFIG) -c "transport select jtag; init; svf chiselwatt.svf; exit"
apps_dir = ./samples
hello_world:
docker run -it --rm -w /build -v $(PWD):/build carlosedp/crossbuild-ppc64le make -C $(apps_dir)/hello_world
@scripts/bin2hex.py $(apps_dir)/hello_world/hello_world.bin > ./insns.hex
micropython:
@if [ ! -d "$(apps_dir)/micropyton/ports/powerpc" ] ; then \
rm -rf $(apps_dir)/micropyton; \
echo "Cloning micropython repo into $(apps_dir)/micropyton"; \
git clone https://github.com/micropython/micropython.git $(apps_dir)/micropyton; \
else \
echo "Micropython repo exists, updating..."; \
cd "$(apps_dir)/micropyton"; \
git pull; \
fi
@docker run -it --rm -v $(PWD):/build carlosedp/crossbuild-ppc64le make -C $(apps_dir)/micropyton/ports/powerpc
@scripts/bin2hex.py $(apps_dir)/micropyton/ports/powerpc/build/firmware.bin > ./insns.hex
clean:
@rm -f Core.fir firrtl_black_box_resource_files.f Core.v Core.anno.json MemoryBlackBox.v
@rm -rf obj_dir test_run_dir target project
@rm -f chiselwatt
@rm -f *.bit *.json *.svf *.config
@rm -f LoadStoreInsns.hex MemoryBlackBoxInsns.hex
@make -C $(apps_dir)/hello_world clean
.PHONY: clean prog
.PHONY: clean prog hello_world micropython
.PRECIOUS: chiselwatt.json chiselwatt_out.config chiselwatt.bit

108
README.md
View File

@@ -15,11 +15,13 @@ cd chiselwatt
make
```
* A micropython image is included in the repo. To use it, link the memory image
into chiselwatt:
* The micropython and hello_world sample images are included in the repo. To use
it, link the memory image into chiselwatt:
```sh
ln -s micropython/firmware.hex insns.hex
ln -s samples/binaries/micropython/firmware.hex insns.hex
# or to use the hello_world sample, run
ln -s samples/binaries/hello_world/hello_world.hex insns.hex
```
* Now run chiselwatt:
@@ -39,54 +41,26 @@ make dockerlator
exit
```
## Building micropython from scratch
* You can also build micropython from scratch. If you aren't building natively
on a ppc64le box you will need a cross compiler. This may be available on your
distro, otherwise grab the the powerpc64le-power8 toolchain from [bootlin](https://toolchains.bootlin.com).
If you are cross compiling, point `CROSS_COMPILE` at the toolchain. In the
example below I installed it in usr/local/powerpc64le-power8--glibc--bleeding-edge-2018.11-1/bin/
and the tools begin with `powerpc64-linux-*`:
```sh
git clone https://github.com/micropython/micropython.git
cd micropython
cd ports/powerpc
make CROSS_COMPILE=/usr/local/powerpc64le-power8--glibc--bleeding-edge-2018.11-1/bin/powerpc64le-linux- -j$(nproc)
cd ../../../
```
* Build chiselwatt, import the the micropython image and run it. We use
bin2hex.py to convert a binary file into a series of 64 bit hex values
expected by the tools:
```sh
cd chiselwatt
make
scripts/bin2hex.py ../micropython/ports/powerpc/build/firmware.bin > insns.hex
./chiselwatt
```
## Synthesis using Open Source tools (yosys/nextpnr)
## Synthesizing for FPGAs using Open Source tools (yosys/nextpnr)
Synthesis on FPGAs is supported with yosys/nextpnr. At the moment the tools support
Lattice ECP5 FPGAs. The build process uses Docker images, so no software other than Docker needs
to be installed. If you prefer podman you can use that too, just adjust it in
`Makefile`, `DOCKER=podman`.
Lattice ECP5 FPGAs. The build process uses Docker images, so no software other
than Docker needs to be installed. If you prefer podman you can use that too,
just adjust it in `Makefile`, `DOCKER=podman`.
### hello_world
The `hello_world` example should run everywhere, so start with it. Edit `src/main/scala/Core.scala`
and set memory to 16 kB (`16*1024`):
The `hello_world` example should run everywhere, so start with it.
Edit `src/main/scala/Core.scala` and set memory to 16 kB (`16*1024`):
```
```scala
chisel3.Driver.execute(Array[String](), () => new Core(64, 16*1024, "insns.hex", 0x0))
```
Then link in the hello_world image:
```sh
ln -s hello_world/hello_world.hex insns.hex
ln -s samples/binaries/hello_world/hello_world.hex insns.hex
```
### Building and programming the FPGA
@@ -101,7 +75,7 @@ The `Makefile` currently supports the following FPGA boards by defining the `ECP
For example, to build for the Evaluation Board, run:
```sh
make ECP5_BOARD=evn synth`
make ECP5_BOARD=evn synth
```
and to program the FPGA:
@@ -131,16 +105,16 @@ This means we use twice as much block RAM as you would expect. This also means
Micropython won't fit on an ECP5 85F, because the ~400kB of available BRAM is halved
to ~200k. Micropython requires 384 kB.
Once this is fixed, edit `src/main/scala/Core.scala` and set memory to 384 kB (`384*1024`):
**Once this is fixed**, edit `src/main/scala/Core.scala` and set memory to 384 kB (`384*1024`):
```
```scala
chisel3.Driver.execute(Array[String](), () => new Core(64, 384*1024, "insns.hex", 0x0))
```
Then link in the micropython image:
```sh
ln -s micropython/firmware.hex insns.hex
ln -s samples/binaries/micropython/firmware.hex insns.hex
```
For example, to build for the ULX3S, run:
@@ -155,7 +129,9 @@ and to program the FPGA:
make ECP5_BOARD=ulx3s prog
```
## Simple Python script for reading USB serial port
If you connect to the serial port of the FPGA at 115200 8n1, you should see "Hello World"
and after that all input will be echoed to the output. On Linux, picocom can be used.
Another option below is a simple python script.
```python
#!/usr/bin/python
@@ -178,6 +154,50 @@ while 1:
print("%s" %(byte))
```
## Building from scratch
### Hello World
The hello world sample simply prints "Hello from Chiselwatt, an OpenPower processor!"
and echoes the input back to the terminal as a serial console.
The source is in `./samples/hello_world` and it can be built by `make hello_world`.
The Makefile generates the `insns.hex` file that will be used on the synthesized
core to be run on Verilator or loaded into FPGA.
### Micropython
You can also build micropython from scratch. As a convenience, there is a Makefile
target to cross-build on a Docker container and generate the firmware.
Just run `make micropython` and it will generate the `insns.hex` file that will
be used on the synthesized core to be run on Verilator or loaded into FPGA.
If running on a container is not an option, you need a ppc64le box or a cross compiler.
This may be available on your distro, otherwise grab the the powerpc64le-power8
toolchain from [bootlin](https://toolchains.bootlin.com).
If you are cross compiling, point `CROSS_COMPILE` at the toolchain. In the
example below I installed it in `usr/local/powerpc64le-power8--glibc--bleeding-edge-2018.11-1/bin/`
and the tools begin with `powerpc64-linux-*`:
```sh
git clone https://github.com/micropython/micropython.git
cd micropython
cd ports/powerpc
make CROSS_COMPILE=/usr/local/powerpc64le-power8--glibc--bleeding-edge-2018.11-1/bin/powerpc64le-linux- -j$(nproc)
cd ../../../
```
* Build chiselwatt, import the the micropython image and run it. We use
bin2hex.py to convert a binary file into a series of 64 bit hex values
expected by the tools:
```sh
cd chiselwatt
make
scripts/bin2hex.py ../micropython/ports/powerpc/build/firmware.bin > insns.hex
./chiselwatt
```
## Issues
Now that it is functional, we have a number of things to add:

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,32 @@
# build with docker build -t REPO/crossbuild-ppc64le -f Dockerfile.crossbuild-ppc64le .
FROM debian:buster
ENV DEBIAN_FRONTEND noninteractive
ENV TOOLCHAIN_URL https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64le-power8/tarballs/powerpc64le-power8--glibc--bleeding-edge-2020.02-2.tar.bz2
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
autoconf \
curl \
wget \
git \
python3 \
python3-pip \
bzip2 \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
WORKDIR /build
RUN wget $TOOLCHAIN_URL && \
mkdir -p /opt/powerpc64le-toolchain && \
tar vxf $(basename $TOOLCHAIN_URL) -C /opt/powerpc64le-toolchain --strip-components=1 && \
rm -rf $(basename $TOOLCHAIN_URL)
ENV PATH /opt/powerpc64le-toolchain/bin:$PATH
ENV CROSS_COMPILE powerpc64le-linux-
RUN powerpc64le-linux-gcc --version
CMD ["/bin/bash"]

View File

@@ -40,7 +40,7 @@ a64b5a7d14004a39
60211f0064210000
618c00003d800000
658c0000798c07c6
7d8903a6618c113c
7d8903a6618c1194
480000004e800421
0000000000000000
0000000000000000
@@ -551,36 +551,63 @@ f80100107c7f1b78
0000000000000000
3c40000100000000
7c0802a63842a000
fbe1fff8fbc1fff0
3be000007c7e1b78
f821ffd1f8010010
4bffffad7fc3f378
419d000c7fa3f840
4bfffe8c38210030
3bff00017c7ef8ae
4bffffdc4bffff15
0100000000000000
3c40000100000280
7c0802a63842a000
3fe2fffffbe1fff8
f80100103bff7190
4bfffec1f821ffd1
4bffffad7fe3fb78
7fe3fb787c641b78
4bfffee94bffff59
4bffff195463063e
000000004bfffff4
f80100103bff7240
4bfffe69f821ffd1
386372003c62ffff
3c62ffff4bffff85
4bffff7938637238
5463063e4bfffe8d
409e00102b83000d
4bffff617fe3fb78
4bfffea94bffffe8
000000004bffffe0
0000018001000000
6f57206f6c6c6548
0000000a0d646c72
7266206f6c6c6548
6573696843206d6f
61202c747461776c
6f506e65704f206e
636f727020726577
0a0d21726f737365
0000000000000000
000000000000203e
00000000203e0a0d
0000000000000010
0141780400527a01
0000001000010c1b
fffffe5800000018
fffffdb000000018
0000000000000040
0000002c00000010
00000038fffffe84
00000038fffffddc
0000001000000000
fffffea800000040
fffffe0000000040
0000000000000034
0000005400000028
00000050fffffec8
00000050fffffe20
9f029e0041094500
437e4111300e4401
4106dedf41000e0a
000000100000000b
fffffeec00000080
fffffe4400000080
000000000000002c
000000940000001c
00000054ffffff04
44019f0041094400
0000007e4111300e
0000009400000028
00000058fffffe5c
9f029e0041094500
457e4111300e4401
4106dedf41000e0a
0000001c0000000b
fffffe88000000c0
410944000000006c
4111300e44019f00
000000000000007e

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,28 @@
ARCH = $(shell uname -m)
ifneq ("$(ARCH)", "ppc64")
ifneq ("$(ARCH)", "ppc64le")
CROSS_COMPILE = powerpc64le-linux-
endif
endif
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS = -Os -g -Wall -std=c99 -msoft-float -mno-string -mno-multiple -mno-vsx -mno-altivec -mlittle-endian -fno-stack-protector -mstrict-align -ffreestanding -fdata-sections -ffunction-sections
ASFLAGS = $(CFLAGS)
LDFLAGS = -T powerpc.lds
all: hello_world.bin
hello_world.elf: hello_world.o head.o
$(LD) $(LDFLAGS) -o hello_world.elf hello_world.o head.o
hello_world.bin: hello_world.elf
$(OBJCOPY) -O binary hello_world.elf hello_world.bin
hello_world.hex: hello_world.bin
../../scripts/bin2hex.py hello_world.bin > hello_world.hex
clean:
@rm -f *.o hello_world.elf hello_world.bin hello_world.hex

107
samples/hello_world/head.S Normal file
View File

@@ -0,0 +1,107 @@
/* Copyright 2013-2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define STACK_TOP 0x2000
#define FIXUP_ENDIAN \
tdi 0,0,0x48; /* Reverse endian of b . + 8 */ \
b 191f; /* Skip trampoline if endian is good */ \
.long 0xa600607d; /* mfmsr r11 */ \
.long 0x01006b69; /* xori r11,r11,1 */ \
.long 0x05009f42; /* bcl 20,31,$+4 */ \
.long 0xa602487d; /* mflr r10 */ \
.long 0x14004a39; /* addi r10,r10,20 */ \
.long 0xa64b5a7d; /* mthsrr0 r10 */ \
.long 0xa64b7b7d; /* mthsrr1 r11 */ \
.long 0x2402004c; /* hrfid */ \
191:
/* Load an immediate 64-bit value into a register */
#define LOAD_IMM64(r, e) \
lis r,(e)@highest; \
ori r,r,(e)@higher; \
rldicr r,r, 32, 31; \
oris r,r, (e)@h; \
ori r,r, (e)@l;
.section ".head","ax"
/*
* Microwatt currently enters in LE mode at 0x0, so we don't need to
* do any endian fix ups>
*/
. = 0
.global _start
_start:
b boot_entry
/* QEMU enters at 0x10 */
. = 0x10
FIXUP_ENDIAN
b boot_entry
. = 0x100
FIXUP_ENDIAN
b boot_entry
.global boot_entry
boot_entry:
/* setup stack */
LOAD_IMM64(%r1, STACK_TOP - 0x100)
LOAD_IMM64(%r12, main)
mtctr %r12,
bctrl
b .
#define EXCEPTION(nr) \
.= nr; \
b .
/* More exception stubs */
EXCEPTION(0x300)
EXCEPTION(0x380)
EXCEPTION(0x400)
EXCEPTION(0x480)
EXCEPTION(0x500)
EXCEPTION(0x600)
EXCEPTION(0x700)
EXCEPTION(0x800)
EXCEPTION(0x900)
EXCEPTION(0x980)
EXCEPTION(0xa00)
EXCEPTION(0xb00)
EXCEPTION(0xc00)
EXCEPTION(0xd00)
EXCEPTION(0xe00)
EXCEPTION(0xe20)
EXCEPTION(0xe40)
EXCEPTION(0xe60)
EXCEPTION(0xe80)
EXCEPTION(0xf00)
EXCEPTION(0xf20)
EXCEPTION(0xf40)
EXCEPTION(0xf60)
EXCEPTION(0xf80)
#if 0
EXCEPTION(0x1000)
EXCEPTION(0x1100)
EXCEPTION(0x1200)
EXCEPTION(0x1300)
EXCEPTION(0x1400)
EXCEPTION(0x1500)
EXCEPTION(0x1600)
#endif

View File

@@ -0,0 +1,164 @@
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
/*
* Core UART functions to implement for a port
*/
static uint64_t potato_uart_base;
#define PROC_FREQ 50000000
#define UART_FREQ 115200
#define UART_BASE 0xc0002000
#define POTATO_CONSOLE_TX 0x00
#define POTATO_CONSOLE_RX 0x08
#define POTATO_CONSOLE_STATUS 0x10
#define POTATO_CONSOLE_STATUS_RX_EMPTY 0x01
#define POTATO_CONSOLE_STATUS_TX_EMPTY 0x02
#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
static uint64_t potato_uart_reg_read(int offset)
{
uint64_t addr;
uint64_t val;
addr = potato_uart_base + offset;
val = *(volatile uint64_t *)addr;
return val;
}
static void potato_uart_reg_write(int offset, uint64_t val)
{
uint64_t addr;
addr = potato_uart_base + offset;
*(volatile uint64_t *)addr = val;
}
static int potato_uart_rx_empty(void)
{
uint64_t val;
val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
if (val & POTATO_CONSOLE_STATUS_RX_EMPTY)
return 1;
return 0;
}
static int potato_uart_tx_full(void)
{
uint64_t val;
val = potato_uart_reg_read(POTATO_CONSOLE_STATUS);
if (val & POTATO_CONSOLE_STATUS_TX_FULL)
return 1;
return 0;
}
static char potato_uart_read(void)
{
uint64_t val;
val = potato_uart_reg_read(POTATO_CONSOLE_RX);
return (char)(val & 0x000000ff);
}
static void potato_uart_write(char c)
{
uint64_t val;
val = c;
potato_uart_reg_write(POTATO_CONSOLE_TX, val);
}
static unsigned long potato_uart_divisor(unsigned long proc_freq, unsigned long uart_freq)
{
return proc_freq / (uart_freq * 16) - 1;
}
void potato_uart_init(void)
{
potato_uart_base = UART_BASE;
potato_uart_reg_write(POTATO_CONSOLE_CLOCK_DIV, potato_uart_divisor(PROC_FREQ, UART_FREQ));
}
int getchar(void)
{
while (potato_uart_rx_empty())
/* Do nothing */;
return potato_uart_read();
}
void putchar(unsigned char c)
{
while (potato_uart_tx_full())
/* Do Nothing */;
potato_uart_write(c);
}
void putstr(const char *str, unsigned long len)
{
for (unsigned long i = 0; i < len; i++)
{
putchar(str[i]);
}
}
void puts(const char *str)
{
for (unsigned long i = 0; i < strlen(str); i++)
{
putchar(str[i]);
}
}
size_t strlen(const char *s)
{
size_t len = 0;
while (*s++)
len++;
return len;
}
#define HELLO_WORLD "Hello from Chiselwatt, an OpenPower processor!\r\n"
#define CLEAR "\033[2K"
int main(void)
{
potato_uart_init();
puts(HELLO_WORLD);
puts("> ");
while (1)
{
unsigned char c = getchar();
if (c == '\r')
{
puts("\r\n> ");
}
else
{
putchar(c);
}
}
}

View File

@@ -0,0 +1,13 @@
SECTIONS
{
_start = .;
. = 0;
.head : {
KEEP(*(.head))
}
. = 0x1000;
.text : { *(.text) }
. = 0x2000;
.data : { *(.data) }
.bss : { *(.bss) }
}

1
samples/micropyton Submodule

Submodule samples/micropyton added at 0bfd55afbe

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/env python3
import sys
import subprocess

View File

@@ -12,7 +12,7 @@ tempdir = tempfile.TemporaryDirectory()
cwd = os.getcwd()
os.chdir(tempdir.name)
copyfile(os.path.join(cwd, 'micropython/firmware.hex'),
copyfile(os.path.join(cwd, 'samples/binaries/micropython/firmware.hex'),
os.path.join(tempdir.name, 'insns.hex'))
cmd = [ os.path.join(cwd, 'chiselwatt') ]