Forth - how to implement words to access bitfields in the hardware register?

Viewed 176

I use Forth for interactive debugging and automatic initialization of the FPGA-based hardware (see https://github.com/wzab/AFCK_J1B_FORTH ). Last time I started to add the support for bitfields in the registers accessible via IPbus or Wishbone bus. Below is my implementation of the words used for reading and writing of the bitfields:

\ This file implements bitfield operations
\ It assumes, that we have the bus access
\ words:
\ wb@ ( address -- val )
\ wb! ( val address -- )
\ The bitfield is defined by its mask
\ (the ones correspond to the bits used by the field)
\ and by its shift (position of the LSB in the cell)

: bf@ ( address mask shift -- val )
  rot ( mask shift address )
  wb@ ( mask shift val )
  rot ( shift val mask )
  and ( shift val )
  swap ( val shift )
  rshift ( val )
;

: bf! ( val address mask shift -- )
  rot ( val mask shift address )
  >r ( val mask shift ) ( R: address )
  rot (  mask shift val ) ( R: address )
  swap (  mask val shift ) ( R: address )
  lshift ( mask val ) ( R: address )
  over ( mask val mask ) ( R: address )
  and ( mask val ) ( R: address )
  swap invert ( val ^mask ) ( R: address )
  r@ ( val ^mask address )  ( R: address )
  wb@ ( val ^mask oldval ) ( R: address )
  and ( val oldval-masked) ( R: address )
  or ( val ) ( R: address )
  r> ( val address )
  wb!
;

The above implementation seems to work, however I'm afraid it is not optimal. Can they be written in a smarter way? It is required, however, that the implementation must be compatible with the Swapforth running on J1B CPU.

1 Answers

I'm not sure, what kind of improvement you expect. While probably faster, your definition of bf! is too monolithic to be forth-like and nothing I would like to maintain.

Starting from these assumptions:

  • Swapforth-compatibility means to do everything on the stacks without locals (if you mean someting else, please clarify)
  • The value and mask supplied are supplied in same right-aligned format (to assume the mask is already shifted creates lots of unreasonable combinations)
  • For my environment I stayed with @ and !, you need to replace them by wb@ and wb!

I arrived at the following code:

\ duplicate existing bitfield information on stack
: bf_dup ( n1 n2 n3 -- n1 n2 n3 n1 n2 n3) 
    2dup 2>r ( n1 n2 n3 R: n2 n3)
    rot dup >r -rot ( n1 n2 n3 R: n2 n3 n1)
    r> 2r> ;

: bf@ ( address mask shift -- val) 2>r @ r> rshift r> and ;

: (mask-old-value) ( addr mask shift -- val) lshift invert swap @ and ;

: (trim-shift-new) ( val addr mask shift -- addr new-value )
    2>r swap 2r> ( addr val mask shift)
    -rot and  ( addr shift val_masked)
   swap lshift ;

: bf! ( val address mask shift -- ) bf_dup (mask-old-value) >r
   (trim-shift-new)
   r> or swap ! ;

Testing and actually applying these words is much easier with the following definition:

  \ store address mask shift (zero-based) in this sequence
   : bitfield create rot , swap , , does> dup @ swap cell+ dup @ swap  cell+ @ ;
   hex 2018 7 3 ( address mask shift) bitfield mybitfield
Related