larsbrinkhoff / lbForth

Self-hosting metacompiled Forth, bootstrapping from a few lines of C; targets Linux, Windows, ARM, RISC-V, 68000, PDP-11, asm.js.
GNU General Public License v3.0
414 stars 113 forks source link

RISC-V target #46

Closed larsbrinkhoff closed 7 years ago

larsbrinkhoff commented 7 years ago

We have it from the apigenual department (@nimblemachines) that RISC-V is the next big thing.

larsbrinkhoff commented 7 years ago

Qemu can be used for testing:
https://github.com/riscv/riscv-qemu

scherrey commented 7 years ago

RISC-V is quite a promising architecture. I've been coding against the RISC-V simulator called Spike and also have a few of the Arduino form-compatible HiFive1 boards which are actual silicon instances of the 32bit ISA (albeit with very limited RAM). Excellent environment for a forth-like architecture.

larsbrinkhoff commented 7 years ago

Thanks for the comment. I'm not quite ready to run standalone on hardware devices. I so far require a file system from which to load parts of the system. That's why I have relied heavily on the qemu-user suite of emulators, and similar tools for 68000 and PDP-11. It's a convenient way to try out the ISA.

Of course, it wouldn't be that hard to make a special standalone metacompiled Forth application if necessary.

I don't see that the HiFive1 board has any UART, right? How do you interact with the embedded software?

scherrey commented 7 years ago

Honestly my experience with the HiFive board thus far has just been via the Arduino dev environment on Linux. I installed the software and it recognized the board just like it was an arduino and all my C++ code just worked. It talked via the USB cable so I assumed it had a UART but perhaps it's just bit banging? It's got plenty of CPU available to fake it.

-- Ben

On Fri, Apr 28, 2017 at 2:45 PM, Lars Brinkhoff notifications@github.com wrote:

Thanks for the comment. I'm not quite ready to run standalone on hardware devices. I so far require a file system from which to load parts of the system.

That's why I have relied heavily on the qemu-user suite of emulators, and similar tools for 68000 and PDP-11. It's a convenient way to try out the ISA.

Of course, it's wouldn't be that hard to make a special standalone metacompiled Forth application if necessary.

I don't see that the HiFive1 board has any UART, right? How do you interact with the embedded software?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/larsbrinkhoff/lbForth/issues/46#issuecomment-297931524, or mute the thread https://github.com/notifications/unsubscribe-auth/AA1n_2WdKxCu4Ljm24XIPAafMqDkoKGIks5r0ZkpgaJpZM4NLGLM .

nimblemachines commented 7 years ago

Lars - this is great news!

The HiFive board has a two-channel FTDI chip on board. One channel is used for JTAG; the other is connected to the on-chip UART (there is a hardware UART).

To communicate with the board and download and run code I've been using a pre-built binary of openocd that the RISC-V folks have modified to work with the FE310 chip on the HiFive1. This binary is intended for use by the Arduino IDE, but if you don't want to build your own openocd, you can just grab it and use it yourself.

I haven't yet explored how to get code into the SPI flash. There is a lot of flash - 16 MiB - but not much RAM - only 16 KiB. However, I'm used to getting Forth running on microcontrollers with only 512 bytes of RAM, so it's a relief to be able to put the whole Forth kernel into RAM during testing and not have to bother with understanding how the flash works!

I'm also hoping to get away from using openocd, and instead putting a simple debug stub into the flash that talks over the UART. (This is what I have done with all the other muforth targets.) At that point I can use the second channel of the FTDI to talk to the chip; it just shows up as a USB serial port.

BTW: I had to look up "apigenual" and it wasn't in my dictionary. Do you have a definition?

And - welcome to the RISC-V fold. ;-)

larsbrinkhoff commented 7 years ago

Thanks David!

Great info. It appeared to me that the CPU used a Harvard architecture; I saw a block diagram with separate on-chip SRAMs for code and data. But you say you put the kernel in RAM, so I suppose that's not the case then.

"Apigenual" is my attempt at Latin. It has probably never been used before, and it's probably wrong! But apis means bee and genu means knee.

nimblemachines commented 7 years ago

I had exactly the same confusion!! The RAM looks like it's data RAM only... But it turns out not to be the case. Made my life much simpler.

Ah - genu as in genuflect (bend the knee). ;-)

sorear commented 7 years ago

Rocket is designed as an application core and it currently has a hard dependency on an instruction cache, and can optionally have a data cache.

As configured in the FE310-G000 there is a 16 KiB instruction cache which refills from the same bus that programmed loads and stores go to.

The bus has a second 16 KiB scratchpad memory which is directly program-accessible (not a cache), as well as several MMIO devices, including one that bridges reads to SPI flash.

If you write data into the scratchpad and then execute it, there will be a copy in both memories. If you write data into the SPI flash and then execute it, there will be a copy in the cache memory but it will not take up space in the scratchpad.

(The SPI interface can either bridge read traffic, or send arbitrary commands. By sending arbitrary commands you could do a write under programmed control. 16 KiB of scratchpad… 2–4 BUFFERs anyone?)


qemu-user works quite well, e.g. I've run gcc bootstraps under it. https://hub.docker.com/r/sorear/fedora-riscv-wip/ is an easy way to get started; you can do e.g. dnf install gcc. Beware that the ABI has changed since that image was spun so please don't distribute binaries.

larsbrinkhoff commented 7 years ago

Thanks for the clarification, @sorear! Are you affiliated with SiFive?

When it comes to ABIs, I mostly only care about the ELF executable format. I suppose it's not prone to changes.

sorear commented 7 years ago

Are you affiliated with SiFive?

No.

I mostly only care about the ELF executable format. I suppose it's not prone to changes.

The literal ELF executable format (statically linked binaries) is compatible. .o and .a files are not; .so and -pie files might or might not be.

larsbrinkhoff commented 7 years ago

The instruction set encoding seems pleasant enough. Shouldn't be hard to make an assembler.

larsbrinkhoff commented 7 years ago

Asssembler is done.

What's up with the encoding of the offsets in the jump and branch instructions?!?

nimblemachines commented 7 years ago

Yes, the assembler - for the non-compressed instructions - takes an afternoon to code.

Those immediates are scrambled to make the hardware simpler. Fewer muxes are necessary.

If you think those are nutty/annoying, take a look at the compressed (C extension) instructions. I've thus far put off implementing an assembler and disassembler for them because there are several even more tangled immediates in the C encoding.

On May 4, 2017 5:12 AM, "Lars Brinkhoff" notifications@github.com wrote:

Asssembler is done.

What's up with the encoding of the offset in jump and branch instructions?!?ob

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/larsbrinkhoff/lbForth/issues/46#issuecomment-299167659, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAM-LxjV3gb6oZc5a9D1mn8F8UHD8zqks5r2cC-gaJpZM4NLGLM .

sorear commented 7 years ago

There are a couple of inconsistencies in the "v2.1" description of the C extension, so if you do that I suggest looking at the git version of the spec and checking your work with objdump.

What I did with Go was to add C support in two phases. First I added compression but inserted a c.nop after every 16-bit instruction; this kept all of the addresses the same so I could just disassemble the RVC and non-RVC versions and diff them with only a small amount of sed cleanup. Then once that was done I removed the nops.

nimblemachines commented 7 years ago

Commenting here rather that on the commit that includes the RISC-V assembler.

You should refrain from using "beq x0, x0" as a "branch always" in your if/then/else assembler code.

Here is what it says in the User-level ISA manual v2.1 (p17):

Unlike some other architectures, the RISC-V jump (JAL with rd=x0) instruction should always be used for unconditional branches instead of a conditional branch instruction with an always-true condition. RISC-V jumps are also PC-relative and support a much wider offset range than branches, and will not pressure conditional branch prediction tables.

larsbrinkhoff commented 7 years ago

Wow, thanks for the detailed review!

I initially used jal for unconditional jumps. But I switched to branch instructions because otherwise >resolve would have to do different things for conditional and unconditional branches.

But you're right, I should fix that.

larsbrinkhoff commented 7 years ago

RISC-V target is done.

larsbrinkhoff commented 7 years ago

Oooo, now I want this instead of the HiFive board. An excuse to get to work on that Xtensa target.

https://blog.hackster.io/sifive-unveils-the-first-risc-v-based-arduino-a4d07fe7f21f