Announcing Mecrisp-Quintus, a native code Forth for RV32IM

(Matthias Koch) #1

Dear RISC-V developers,

I am happy to announce Mecrisp-Quintus, a native code Forth for RV32IM instruction set written entirely in assembler. It is available in the download area of

Its first targets are Picosoc by Clifford Wolf on a Lattice HX8K FPGA breakout board, and the LM4F120 Stellaris Launchpad, as I wrote an emulator called Mamihlapinatapai which allows to run RV32IM opcodes on ARM Cortex M3/M4.

Now, it is time to support real RISC-V hardware. It is difficult for me to find an HiFive1 here in Germany, therefore, I am looking for help. Is there a Forth freak who has hardware available and wishes to help ? Technically, a bare metal UART echo written in plain assembler is necessary to port Mecrisp-Quintus to a new piece of hardware, along with adjustments to the memory map.

If you are interested, just drop me a line. I am available for assistance.

Best wishes from Germany and hats off to the SiFive team,

(Matthias Koch) #2

Dear SiFive team,

thank you for donating a board for me thru Jürgen Pintaske, your surprise is very much appreciated and I released Mecrisp-Quintus 0.4 today, with support for the HiFive1.

A disassembler and a s31.32 fixpoint math library by Andrew Palm are included.


(Drew) #3

Wow that was fast :slight_smile:

I will give this a try soon


This is exactly what I am looking for as I build a light-sculpture controller around the HiFive1. I fondly remember my playing with Forth years ago.

(Matthias Koch) #5

Glad to read you ! Let me know how you are coming along with my Forth, and if you have a wish, just drop me a line.


My main stumbling block right now is, how do I interface to the hardware I2C on the HiFive1 Rev B from Forth? Is Mecrisp-Quintus a “bare metal” implementation? Do I need to write an I2C driver in Forth? I can probably find one written in C and translate it, assuming that Quintus provides the basic mechanism for poking the control registers.


Next problem - just trying to build it. The Makefile is looking for ../../toolchain/riscv64-unknown-elf and there is no toolchain directory at all.

(Matthias Koch) #8

Mecrisp-Quintus is bare metal, you need to write your own I2C driver by reading the datasheet of the chip and poking the IO registers mentioned there. By the way, it’s usually easier to bit-bang I2C. Have a look at mecrisp-stellaris-2.5.0/stm32f303/imu.txt for an example. You’ll just have to change the GPIO access code.

\ -----------------------------
\  Bit-Bang I2C Implementation
\ -----------------------------

\ Low-level target specific pin configurations

1 6 lshift constant i2c-scl
1 7 lshift constant i2c-sda

: scl-high ( -- ) i2c-scl           portb_bsrr ! ;
: scl-low  ( -- ) i2c-scl 16 lshift portb_bsrr ! ;
: sda-high ( -- ) i2c-sda           portb_bsrr ! ;
: sda-low  ( -- ) i2c-sda 16 lshift portb_bsrr ! ;

: scl-@    ( -- f ) 20 0 do loop i2c-scl portb_idr bit@ ;
: sda-@    ( -- f ) 20 0 do loop i2c-sda portb_idr bit@ ;

: I2C-Init ( -- ) 

  %01 6 2* lshift
  %01 7 2* lshift or portb_moder  bis!  \ Set both I2C lines as outputs
  i2c-scl i2c-sda or portb_otyper bis!  \ Open Drain mode

  scl-high sda-high \ Bus free default state. During communication, SCL is low for default.

\ Low-Level I2C-Protocol

: I2C-Start ( -- ) sda-high scl-high sda-low scl-low ;
: I2C-Stop  ( -- ) sda-low scl-high sda-high ;

: I2C-Bit-TX ( f -- )
  if sda-high else sda-low then
  scl-high begin scl-@ until

: I2C-Bit-RX ( -- f )

  scl-high begin scl-@ until

\ Higher level I2C-Protocol

: I2C-TX ( b -- f )
  dup $80 and I2C-Bit-TX
  dup $40 and I2C-Bit-TX
  dup $20 and I2C-Bit-TX
  dup $10 and I2C-Bit-TX
  dup $08 and I2C-Bit-TX
  dup $04 and I2C-Bit-TX
  dup $02 and I2C-Bit-TX
      $01 and I2C-Bit-TX

  I2C-Bit-RX 0=

: I2C-RX ( f -- b )
  I2C-Bit-RX $80 and
  I2C-Bit-RX $40 and or
  I2C-Bit-RX $20 and or
  I2C-Bit-RX $10 and or
  I2C-Bit-RX $08 and or
  I2C-Bit-RX $04 and or
  I2C-Bit-RX $02 and or
  I2C-Bit-RX $01 and or

  swap 0= I2C-Bit-TX

\ I2C device detection

: u.2 s>d <# # # #> type ;

: i2c-ping? ( addr - f ) i2c-start shl i2c-tx i2c-stop ;
: i2c-7bitaddr? ( addr -- f ) dup $7 u>= swap $77 u<= and ;

: i2c-detect   ( -- )
  i2c-init cr
    base @ hex
    4 spaces $10 0 do i space u.2 loop

    $80 0 do
      i $0f and 0= if
        cr i u.2 [char] : emit space
      i i2c-7bitaddr? if
        i i2c-ping? if \ does device respond?
            i space u.2
            ."  --" 
         ."    "
    cr base !

Toolchain folder is in as it’s quite large and doesn’t change with subsequent releases.


Bare metal is fine for this application. And it builds now! w00t. I have the Linux version working too. Thank you. I will study the I2C spec and these examples while waiting for my device to arrive. This should be a good way to build my project while also learning the new RISC-V stuff (really tired of Atmel and Cortex M0) and getting back into the innards of Forth.

What is the command to include and compile a Forth source file? Or more generally, exactly which dialect of Forth is this?

(Matthias Koch) #10

Usually, you just send or copy your source file into the terminal. You can use quintusemu to make binaries with precompiled Forth sources inside.

See mecrisp-quintus-0.20-experimental/hifive1/buildcore and mecrisp-quintus-0.20-experimental/release

It’s the Mecrisp dialect - close to ANS-Forth, but not exactly the same. Look at mecrisp-stellaris-2.5.0/common/ansification.txt for differences.