Forth Processor in VHDL

On Saturday 9/2/00 Don Golding at Angelus Research posted the following Forth processor design for FPGA in VHDL and followed with the following statement.

Subject: Forth Processor in VHDL-FP1
Resent-Date: Sat, 2 Sep 2000 16:18:12 -0300 (EDT)
Date: Sat, 02 Sep 2000 12:25:23 -0700
From: Don Golding 
I posted the VHDL code for a Forth Processor created in VHDL for FPGA's, etc.  Here is the deal.  You may use all or part of the code in
your own processors if you share your enhancements for only the Forth Processor Core Design with the MISC list and myself.
This goal of this processor design is KISS (Keep it Simple Stupid).  If the Forth Processor core takes up less than 50% of the FPGA in
your design, then you can have concurrent processes for those other functions you need great speed for.  Remember, the most exciting
thing about using VHDL to create custom FPGA's is they are really you are creating parallel processors on a single chip.  I think a super
fast Forth core which can execute multiple instructions per cycle is really not necessary for most applications.  The Forth Processor will
allow programming capabilities and off load low speed processes that don't need speed.  This will allow us to use smaller and cheaper
FPGA's and give field programming as well.
I think Forth could get its crown back as the embedded system language of choice this way.

Subject: Fw: p16 is VHDL
Resent-Date: Wed, 30 Aug 2000 19:26:29 -0300 (EDT)
Date: Wed, 30 Aug 2000 15:33:34 -0700
From: Don Golding 
To: "Misc,List" 

This code will synthesize using Xilinx Foundation tools.  I am too busy to
finish this, but if someone wants to take the ball, I would fully support
them...Please contact me if you are interested...

-- Don Golding
-- Angelus Research Corp.
-- Version 4
--                       Forth Processor Design
-- This code represents my current thoughts on designing a Forth Processor in VHDL.
-- Please review it and email me with your input on either Forth design issues or
-- VHDL design issues.
-- The goal is to build a generic Forth processor that can be included in VHDL designs.
-- It does synthesize using the Xilinx Foundation
-- Forth is really a virtual microprocessor implemented on other various processors
-- from 68HC11 to VAX machines and supercomputers.  You will currently find Forth used
-- as the driver for PCI hardware in high end Macintosh's and Sun Workstations.
-- This is an attempt to create a real Forth Processor on an FPGA or ASIC using VHDL.
-- Previous real Forth Microprocessors include: Harris RTX2000, SHABOOM, F21,etc.
-- The current attempts F21, etc. are trying to make 500mips screamers.
-- There are also people like Dr. Ting using the Schematic editor to create Forth
-- processors.  I wonder how a Schematic designed Forth processor will compare to a VHDL
-- based design in speed and the number of gates used.

-- I think a straight forward simple design will have considerable applications
-- when you need a processor included in your FPGA/ASIC design.
-- FPGA operate at 200mhz, I don't know how fast this design will be, but it's speed
-- should be limited to the external RAM speed when memory access is required.
-- Internal register to register operations should be 50-200mhz range.
-- The preliminary specifications are:
--  16 bit data bus (to save space, could be 8 bit but it would take more statements)
--  16 bit address bus
--  by editing the code in the Entity declariations, you implement 32, 64, ? designs
--  Return Stack levels=16
--  Data Stack levels=16 (could be smaller, 4 items could be ok)
--  Output port A is 8 lines
--  Output port B is 8 lines
--  Motorola SPI compatible port (SPI_In,SPI_Out,SPI_Ck,SS/)
--  By editing the code in the Entity declariations, you can add serial ports, parallel
--  ports, adc's or just about anything you can imagine.

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

entity Proc is

generic (
  address_size       : integer := 15;
  data_size          : integer := 15;
  stack_depth        : integer := 3;
  port_size          : integer := 7;
  code_size          : integer :=4

port (
        data:    buffer STD_LOGIC_VECTOR (data_size downto 0);
        address: buffer STD_LOGIC_VECTOR (address_size downto 0);
        reset:   buffer STD_LOGIC;
        clock:   buffer STD_LOGIC;
        rd:      buffer std_logic
end Proc;

architecture Proc_arch of Proc is

--buffered, low-skew clock signal
  component ibuf port(I: in std_logic; O: out std_logic); end component;
  component bufg port(I: in std_logic; O: out std_logic); end component;
  signal buf_clock, bufg_clock: std_logic;

   type bit_pointer is array (data_size downto 0) of std_logic;
   type data_word is array   (data_size downto 0) of STD_LOGIC;
   type pointer_type is array (stack_depth downto 0) of STD_LOGIC;
   type stack_type is array   (stack_depth downto 0) of
             std_logic_vector(data_size downto 0);

   constant dstack_start:pointer_type:="0000";
   constant write:STD_LOGIC:='0';
   constant read:STD_LOGIC:='1';

    --Errorcodes are defined here
   constant dstack_overflow:     data_word    :="0000000000000001";
   constant dstack_underflow:    data_word    :="0000000000000010";
   constant rstack_overflow:     data_word    :="0000000000000011";
   constant rstack_underflow:    data_word    :="0000000000000100";
   constant invalid_instruction: data_word    :="0000000000000101";
   constant no_errors:           data_word    :="0000000000000000";
   constant is_true:             data_word    :="1111111111111111";
   constant is_false:            data_word    :="0000000000000000";

   constant abort:               std_logic_vector(code_size downto 0)    :="00001";
   constant depth:               std_logic_vector(code_size downto 0)    :="00010";
   constant dup:                 std_logic_vector(code_size downto 0)    :="00101";
   constant pick:                std_logic_vector(code_size downto 0)    :="00110";
   constant over:                std_logic_vector(code_size downto 0)    :="00111";
   constant swap:                std_logic_vector(code_size downto 0)    :="01000";
   constant to_return:           std_logic_vector(code_size downto 0)    :="01001";
   constant from_return:         std_logic_vector(code_size downto 0)    :="01011";
   constant copy_return:         std_logic_vector(code_size downto 0)    :="01100";
   constant drop:                std_logic_vector(code_size downto 0)    :="01101";
   constant rot:                 std_logic_vector(code_size downto 0)    :="01110";
   constant equal:               std_logic_vector(code_size downto 0)    :="01111";
   constant zero_equal:          std_logic_vector(code_size downto 0)    :="10000";
   constant greater_than:        std_logic_vector(code_size downto 0)    :="10001";
   constant less_than:           std_logic_vector(code_size downto 0)    :="10011";
   constant store:               std_logic_vector(code_size downto 0)    :="10100";
   constant plus_store:          std_logic_vector(code_size downto 0)    :="10101";
   constant fetch:               std_logic_vector(code_size downto 0)    :="10110";
   constant plus:                std_logic_vector(code_size downto 0)    :="10111";
   constant minus:               std_logic_vector(code_size downto 0)    :="11000";
   constant times:               std_logic_vector(code_size downto 0)    :="11001";
   constant divide:              std_logic_vector(code_size downto 0)    :="11010";
   constant branch:              std_logic_vector(code_size downto 0)    :="11011";
   constant zero_branch:         std_logic_vector(code_size downto 0)    :="11100";

  signal reset_line            : STD_LOGIC;
  signal clock_line            : STD_LOGIC;
  signal rd_line               : STD_LOGIC;
  signal DataBuss              : STD_LOGIC_VECTOR (15 downto 0);
  signal AddressBuss           : STD_LOGIC_VECTOR (15 downto 0);
  signal data_stack            : stack_type;
  signal return_stack          : stack_type;

  signal rp:integer;      -- return stack pointer
  signal dp:integer;      --  data stack pointer
  signal mp:STD_LOGIC_VECTOR (15 downto 0);      -- integermemory pointer

  signal errorcode:data_word;
  signal successful:std_logic;
  signal opcode:std_logic_vector(code_size downto 0);
 -- signal reset:std_logic;


  rp <=0;
  dp <=0;
  mp <="0000000000000000";
  rd_line <= read;
  reset_line <='1';
  clock_line <='0';

  DataBuss <= "0000000000000000";
  AddressBuss <= "0000000000000000";

process (opcode,dp,rp,mp,data_stack,return_stack,DataBuss,AddressBuss)

      --Forth stack manipulation primitives
      --I think we should implement a circular que here.
      --data_stack(dp) points to next available location, can use as temp
      --before using push_dp_stack or pop_dp_stack procedures.
      --each stack are really 16 registers!  Stack operations should be real fast!

   procedure reset_proc is


        rd_line <=read;

   end reset_proc;

   procedure push_dp_stack is
   -- dp points the the next stack element not the current one after operation is completed.


            if dp = 16 then
               dp <= dp+1;
            end if;

   end push_dp_stack;

   procedure pop_dp_stack is
   -- dp points the the next stack element not the current one after operation is completed.

            if dp = 0 then
               dp <= dp-1;
            end if;

   end pop_dp_stack;

   procedure push_rp_stack is
   -- dp points the the next stack element not the current one after operation is completed.


            if rp = 16 then
               rp <= rp+1;
            end if;

   end push_rp_stack;

   procedure pop_rp_stack is
   -- dp points the the next stack element not the current one after operation is completed.


            if rp = 0 then
               rp <= rp-1;
            end if;
   end pop_rp_stack;

   procedure up_dp_stack is
     -- dp points the the next stack element not the current one after operation is completed.


     end up_dp_stack;

   procedure proc_code is


      opcode <= DataBuss(code_size downto 0);

        if opcode=abort then


--        elsif opcode=depth then -- put the depth of the stack on the top

--             data_stack(dp) <= dp;
--             up_dp_stack;

           elsif opcode=dup then   --duplicate the top item on data stack


           elsif opcode=pick then  --get on data stack pointed to by TOS


           elsif opcode=over then  --duplicate the second number on data stack

             data_stack(dp) <= data_stack(dp+2);

          elsif opcode=swap then  --swap top two numbers on data stack

             return_stack(rp) <= data_stack(dp+1);
             data_stack(dp+1) <= data_stack(dp+2);
             data_stack(dp+2) <= return_stack(rp);

          elsif opcode=to_return then  --move top of data stack to return stack

             return_stack(rp) <= data_stack(dp+1);

          elsif opcode=from_return then  --move top of return stack to data stack

             data_stack(dp+1) <= return_stack(rp+1);

          elsif opcode=copy_return then  --move top of return stack to data stack

             data_stack(dp) <= return_stack(rp+1);

          elsif opcode=drop then  --drop top number from data stack


          elsif opcode=rot then  --rotate 3rd numbr to 1st on data stack

            return_stack(rp) <= data_stack(dp+1);
            data_stack(dp+1) <= data_stack(dp+3);

           elsif opcode=equal then  -- if tos and second are equal then true

             if data_stack(dp+1)=data_stack(dp+2) then
             end if;

          elsif opcode=zero_equal then  -- if tos=0 then tos=true

             if data_stack(dp+1)= "0000000000000000" then
             end if;

          elsif opcode=greater_than then  -- if tos is greater then the sec then tos=true

             if data_stack(dp+1)>data_stack(dp+2) then
             end if;

          elsif opcode=less_than then  -- if tos is less than the second item then tos=true

             if data_stack(dp+1)clock, O=>buf_clock);
buf2: bufg port map(I=>buf_clock, O=>bufg_clock);

process (bufg_clock,AddressBuss, DataBuss,reset,reset_line,rd_line)


  rd <= rd_line;
  reset_line <= reset;
  clock_line <= buf_clock;

  if reset_line='1' then

     opcode <= fetch;
     rp <=0;
     dp <=0;
     AddressBuss <="0000000000000000";
     DataBuss    <="0000000000000000";
     Data <= DataBuss;
     Address <= AddressBuss;

  elsif (bufg_clock'event and bufg_clock='1') then

      rp <=0;
      dp <=0;
      Address <= AddressBuss;

      if rd_line=read then
         DataBuss <= Data;
         Data <= DataBuss;
      end if;

  end if;

end process;

end Proc_arch;

Don Golding
Angelus Research Corp.
Angelus Research .com

Also, check out for the latest breaking news in technology and robotics, updated daily!

Posted: 9/2/2000

page created by Jeff Fox

UltraTechnology homepage