home .. forth .. misc mail list archive ..

Re: p16 is VHDL


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.
-- dgolding@angelusresearch.com
-- 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";
 
   --opcodes
   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;
 
begin
 
  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 variable
      --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
 
   begin
 
        rd_line <=read;
        errorcode<=no_errors;
        dp<=0;
        rp<=0;
       
   end reset_proc;
 
   procedure push_dp_stack is
   -- dp points the the next stack element not the current one after operation is completed.
  
   begin
  
            if dp = 16 then
               errorcode<=dstack_overflow;
               reset_proc;
            else
               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.  
   begin
  
            if dp = 0 then
               errorcode<=dstack_underflow;
               reset_proc;
            else
               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.
     
   begin
  
            if rp = 16 then
               errorcode<=rstack_overflow;
               reset_proc;
            else
               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.
  
   begin
  
            if rp = 0 then
               errorcode<=rstack_underflow;
               reset_proc;
            else
               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.
  
     begin
  
     end up_dp_stack;
  
   procedure proc_code is
  
      begin
 
      opcode <= DataBuss(code_size downto 0);
      successful<='1';
  
        if opcode=abort then
            
             reset_proc;
 
          
--        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
            
             data_stack(dp)<=data_stack(dp+1);
             up_dp_stack;
         
           elsif opcode=pick then  --get on data stack pointed to by TOS
 
             data_stack(dp)<=data_stack(dp+1);
             up_dp_stack;
 
           elsif opcode=over then  --duplicate the second number on data stack
 
             data_stack(dp) <= data_stack(dp+2);
              up_dp_stack;
         
          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);
             pop_dp_stack;
             push_rp_stack;
            
          elsif opcode=from_return then  --move top of return stack to data stack
 
             data_stack(dp+1) <= return_stack(rp+1);
             pop_rp_stack;
             push_dp_stack;
            
          elsif opcode=copy_return then  --move top of return stack to data stack
 
             data_stack(dp) <= return_stack(rp+1);
             push_dp_stack;
         
          elsif opcode=drop then  --drop top number from data stack
 
               pop_dp_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
                pop_dp_stack;
                data_stack(dp+1)<="1111111111111111";
             end if;  
         
          elsif opcode=zero_equal then  -- if tos=0 then tos=true
            
             if data_stack(dp+1)= "0000000000000000" then
                data_stack(dp+1)<="1111111111111111";
             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
                pop_dp_stack;
                data_stack(dp+1)<="1111111111111111";
             end if;  
 
          elsif opcode=less_than then  -- if tos is less than the second item then tos=true
            
             if data_stack(dp+1)<data_stack(dp+2) then
                pop_dp_stack;
                data_stack(dp+1)<="1111111111111111";
             end if;  
         
          elsif opcode=store then  -- store 16 bit value to memory
 
            rd_line<=read;
            addressBuss <= data_stack(dp+1);
            dataBuss <= data_stack(dp+2);
            pop_dp_stack;
            pop_dp_stack;
         
           elsif opcode=plus_store then  -- increment 16 bit value in memory
 
            rd_line<=read;
            AddressBuss <= data_stack(dp+1);
            DataBuss <= DataBuss+data_stack(dp+1);
            rd_line<=write;
            pop_dp_stack;
            pop_dp_stack;
            rd_line<=read;  -- probably need a delay here
 
          elsif opcode=fetch then -- get 16 bit value from memory
           
            rd_line<=read;
            data_stack(dp) <= DataBuss;
            push_dp_stack;
 
          elsif opcode=plus then  --add two 16 bit numbers
            
             data_stack(dp+1) <= data_stack(dp+2) + data_stack(dp+1);
             pop_dp_stack;
 
          elsif opcode=minus then --subtract two 16 bit numbers
            
             data_stack(dp+2) <= data_stack(dp+1) - data_stack(dp+2);
             pop_dp_stack;
 
          elsif opcode=branch then --branch unconditionally
           
             mp<=mp+1;
             rd_line<=read;
             AddressBuss<=DataBuss;
            
          elsif opcode=zero_branch then --branch if tos = 0
            
             if data_stack(dp+1)="0000000000000000" then
                mp<=mp+1;
                rd_line<=read;
                AddressBuss<=DataBuss;
                mp<=DataBuss;
             end if;  
 
        else -- not an opcode
            successful<='0';
       end if;
                          
      end proc_code;
 
   begin
 
     opcode<=dataBuss(code_size downto 0);
     proc_code;
 
end process;      
 
buf1: ibuf port map(I=>clock, O=>buf_clock);
buf2: bufg port map(I=>buf_clock, O=>bufg_clock);
 
process (bufg_clock,AddressBuss, DataBuss,reset,reset_line,rd_line)
 
  begin
 
  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;
      else
         Data <= DataBuss;
      end if;    
    
  end if;
 
end process;
   
end Proc_arch;
 
 
 
Also, check out http://www.futurenews.org for the latest breaking news in technology and robotics, updated daily!