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) Resent-From: MISC@pisa.rockefeller.edu Date: Sat, 02 Sep 2000 12:25:23 -0700 From: Don GoldingI 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) Resent-From: MISC@pisa.rockefeller.edu Date: Wed, 30 Aug 2000 15:33:34 -0700 From: Don GoldingTo: "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. -- 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"; --opcode 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)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 www.futurenews.org for the latest breaking news in technology and robotics, updated daily!
page created by Jeff Fox