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!
|