--VHDL --~ ------------------------------------------------------ -- uCore 1.90 - constants.vhd -- -- -------------------------------------------------------------- -- -- Author: KLAUS SCHLEISIEK -- Last change: KS 08.12.2015 12:03:37 -- -- Do not use this file except in compliance with the License. You may -- obtain a copy of the License at http://www.microcore.org/License/ -- Software distributed under the License is distributed on an "AS IS" basis, -- WITHOUT WARRANTY OF ANY KIND, either express or implied. -- See the License for the specific language governing rights and limitations -- under the License. -- -- The Initial Developer of the Original Code is Klaus.Schleisiek AT microcore.org. -- -- Defining all MicroCore bus-widths and records, as well as the opcode fields. -- This file is also used by the cross-compiler. LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE work.functions.ALL; PACKAGE constants IS --~-- \ when loaded by the Forth cross-compiler, code between "--~" up to "--~--" will be skipped. CONSTANT version : NATURAL := 190; -- async_reset is defined in functions.vhd, because that is the first file to load -- CONSTANT async_reset : BOOLEAN := false; -- true = async reset, false = synchronous reset CONSTANT simulation : BOOLEAN := true ; -- will increase the frequency of timers to make them observable in simulation CONSTANT syn_stackram : BOOLEAN := true ; -- true when stack ram will be realised by block ram CONSTANT with_mult : BOOLEAN := true ; -- true when FPGA has hardware multiply resources CONSTANT with_tasks : BOOLEAN := true ; -- true when TASK+TOS addressing mode CONSTANT sat_arith : BOOLEAN := false ; -- true when result is set to max or min on overflow CONSTANT with_bytes : BOOLEAN := false ; -- true with dmem read-modify-write 8b and 16b instructions CONSTANT with_float : BOOLEAN := true ; -- floating point instructions? -- CONSTANT vco_frequency : NATURAL := 10000000; -- Hz used when a PLL generates the processor clock CONSTANT sys_frequency : NATURAL := 12288000; -- Hz CONSTANT phase_1 : NATURAL := 1; -- number of cycles for address computation phase CONSTANT phase_2 : NATURAL := 1; -- number of cycles for memory access & execution phase CONSTANT umbilical_rate : NATURAL := 115200; --~ CONSTANT MEM_file : string := "../uForth/program.mem"; CONSTANT DMEM_file : string := "none"; --"../uForth/data.mem"; --~-- -- ----------------------------------------------------------------------- -- microcore busses -- ----------------------------------------------------------------------- CONSTANT data_width : NATURAL := 32; -- data bus width CONSTANT inst_width : NATURAL := 8; -- instruction width CONSTANT exp_width : NATURAL := 8; -- floating exponent width CONSTANT prog_addr_width : NATURAL := 12; -- program memory address width CONSTANT pcache_addr_width : NATURAL := 12; -- prog. cache memory address width CONSTANT prog_ram_width : NATURAL := 12; -- writeable program memory address width, at most data_addr_width-2 -- 0 => program memory can not be written CONSTANT boot_addr_width : NATURAL := 6; -- size of the internal boot program memory CONSTANT ds_addr_width : NATURAL := 5; -- data stack pointer width CONSTANT tasks_addr_width : NATURAL := 3; -- 2**tasks_addr_width copies of the stack areas will be provided -- ----------------------------------------------------------------------- -- data memory parameters: -- data_addr_width > tasks_addr_width+rs_addr_width -- program-memory address has msb set, in the upper half of the address room -- ----------------------------------------------------------------------- CONSTANT data_addr_width : NATURAL := 12; -- data memory address width, at most data_width-1 because of I/O space CONSTANT dcache_addr_width : NATURAL := 9; -- data cache memory address width, at most see "data_addr_width" CONSTANT rs_base_width : NATURAL := 12; -- return stack base address width - data_width-rs_base_width = number of leading '0's of rstack address; data_width must be at least 1 larger than rs_base_width CONSTANT rs_addr_width : NATURAL := 5; -- return stack pointer width CONSTANT usr_vect_width : NATURAL := 3; -- each vector has room for 2**usr_vec_width instructions CONSTANT reg_addr_width : NATURAL := 5; -- number of address bits reserved for internal registers at the top data space CONSTANT signbit : NATURAL := data_width-1; -- signbit is used to control set/reset of bit wise writeable registers --~ CONSTANT data_nibbles : NATURAL := ceiling(data_width, 8); -- ----------------------------------------------------------------------- -- internal and memory mapped registers (addr < 0) -- ----------------------------------------------------------------------- TYPE status_register IS RECORD c : STD_LOGIC; -- carry ovfl : STD_LOGIC; -- integer and float overflow ie : STD_LOGIC; -- interrupt enable iis : STD_LOGIC; -- interrupt in service lit : STD_LOGIC; -- previous instruction was lit_instruction n : STD_LOGIC; -- sign z : STD_LOGIC; -- zero div : STD_LOGIC; -- sign of division den : STD_LOGIC; -- sign of DividENd word : STD_LOGIC; -- previous wLD='1', cLD='0' unfl : STD_LOGIC; -- float underflow fwrd : STD_LOGIC; -- sign indicator for the TIMES instruction END RECORD; --~-- CONSTANT c_bit : NATURAL := 0; -- carry bit CONSTANT ovfl_bit : NATURAL := 1; -- Overflow-bit of UDIVS instruction CONSTANT ie_bit : NATURAL := 2; -- Interrupt Enable bit CONSTANT iis_bit : NATURAL := 3; -- InterruptInService bit CONSTANT lit_bit : NATURAL := 4; -- LIT bit of the previous instruction CONSTANT n_bit : NATURAL := 5; -- Sign-bit of top data element (TOS or sometimes NOS) CONSTANT z_bit : NATURAL := 6; -- Zero-bit of top data element (TOS or sometimes NOS) CONSTANT div_bit : NATURAL := 7; -- Sign of Dividend in signed division (op_SDIVS) CONSTANT den_bit : NATURAL := 8; -- Sign of Divisor in signed division (op_SDIVS) CONSTANT word_bit : NATURAL := 9; -- set by w@/!, reset by c@/! CONSTANT unfl_bit : NATURAL := 10; -- underflow set by normalize CONSTANT fwrd_bit : NATURAL := 11; CONSTANT status_width : NATURAL := 12; --~ CONSTANT max_registers : INTEGER := -1; --~-- memory mapped registers CONSTANT INT_REG : INTEGER := -1; -- ints@ and ie! CONSTANT FLAG_REG : INTEGER := -2; -- flags@, pass CONSTANT i_ext : NATURAL := 0; CONSTANT interrupts : NATURAL := 1; -- maskable interrupt sources CONSTANT f_break : NATURAL := 1; -- debug UART break detection CONSTANT f_debug : NATURAL := 2; -- set when debug register is full CONSTANT f_sema : NATURAL := 3; CONSTANT flag_width : NATURAL := 4; CONSTANT green : STD_LOGIC := '0'; -- interpretation of flag value CONSTANT red : STD_LOGIC := '1'; -- when used as semaphor (: pass ( mask -- ) flag_reg ! ;) CONSTANT TASK_REG : INTEGER := -3; -- base register for tld and tst instructions CONSTANT VERSION_REG : INTEGER := -4; -- FPGA Version CONSTANT DEBUG_REG : INTEGER := -5; -- umbilical interface CONSTANT CTRL_REG : INTEGER := -6; -- ctrl@ ctrl! CONSTANT c_sema : NATURAL := 0; CONSTANT ctrl_width : NATURAL := 1; CONSTANT TIME_REG : INTEGER := -7; CONSTANT ticks_per_ms : NATURAL := 4; CONSTANT min_registers : INTEGER := -7; --~ -- ----------------------------------------------------------------------- -- uCore subtype and record definitions -- ----------------------------------------------------------------------- SUBTYPE byte IS STD_LOGIC_VECTOR(7 DOWNTO 0); SUBTYPE data_bus IS STD_LOGIC_VECTOR(data_width-1 DOWNTO 0); SUBTYPE exponent IS STD_LOGIC_VECTOR(exp_width-1 DOWNTO 0); SUBTYPE inst_bus IS STD_LOGIC_VECTOR(inst_width-1 DOWNTO 0); SUBTYPE inst_group IS STD_LOGIC_VECTOR(inst_width-6 DOWNTO 0); SUBTYPE data_addr IS STD_LOGIC_VECTOR(data_addr_width-1 DOWNTO 0); SUBTYPE program_addr IS STD_LOGIC_VECTOR(prog_addr_width-1 DOWNTO 0); SUBTYPE boot_addr IS STD_LOGIC_VECTOR(boot_addr_width-1 DOWNTO 0); SUBTYPE reg_bus IS STD_LOGIC_VECTOR( reg_addr_width-1 DOWNTO 0); SUBTYPE ds_addr IS STD_LOGIC_VECTOR(ds_addr_width+tasks_addr_width-1 DOWNTO 0); SUBTYPE rs_addr IS STD_LOGIC_VECTOR(rs_addr_width+tasks_addr_width-1 DOWNTO 0); SUBTYPE int_flags IS STD_LOGIC_VECTOR(interrupts-1 DOWNTO 0); SUBTYPE flag_bus IS STD_LOGIC_VECTOR(flag_width-1 DOWNTO 0); SUBTYPE ctrl_bus IS STD_LOGIC_VECTOR(ctrl_width-1 DOWNTO 0); SUBTYPE status_bus IS STD_LOGIC_VECTOR(status_width-1 DOWNTO 0); TYPE data_sources IS ARRAY (max_registers DOWNTO min_registers) OF data_bus; TYPE data_select IS ARRAY (max_registers DOWNTO min_registers) OF STD_LOGIC; TYPE uBus_port IS RECORD reset : STD_LOGIC; clk : STD_LOGIC; clk_en : STD_LOGIC; -- enable at end of uCore cycle read_en : STD_LOGIC; -- enable signal for memory addresses (data, program, stack) except : STD_LOGIC; delay : STD_LOGIC; tick : STD_LOGIC; -- produces pulse every "ticks_per_ms" sources : data_sources; -- array of register outputs -- data_io_interface enable : STD_LOGIC; -- RAM & IO address space, includes Returnstack write : STD_LOGIC; -- 1 => write, 0 => read addr : data_bus; -- address on uBus reg_addr : reg_bus; -- register select address dout : data_bus; -- data to memory dma : data_bus; -- data from dma memory END RECORD; TYPE core_signals IS RECORD clk_en : STD_LOGIC; read_en : STD_LOGIC; tick : STD_LOGIC; int : data_bus; task : data_bus; time : data_bus; debug : data_bus; END RECORD; TYPE datamem_port IS REcORD enable : STD_LOGIC; -- RAM & IO address space, includes Returnstack write : STD_LOGIC; -- 1 => write, 0 => read reg_addr : reg_bus; -- register select address addr : data_bus; -- address on uBus dout : data_bus; -- data to memory END RECORD; TYPE progmem_port IS RECORD enable : STD_LOGIC; write : STD_LOGIC; addr : program_addr; dout : inst_bus; END RECORD; TYPE from_uart IS RECORD exc : STD_LOGIC; -- uart read exception OUT data : byte; -- input data buffer OUT full : STD_LOGIC; -- data buffer full OUT break : STD_LOGIC; -- break on input line OUT empty : STD_LOGIC; -- data buffer empty OUT busy : STD_LOGIC; -- transmission under way OUT END RECORD; TYPE to_uart IS RECORD read : STD_LOGIC; -- read and clear data buffer IN data : byte; -- output data IN write : STD_LOGIC; -- write into data buffer IN END RECORD; --~-- CONSTANT mark_start : byte := "00110011"; -- umbilical CONSTANT mark_reset : byte := "11001100"; -- control CONSTANT mark_debug : byte := "10101010"; -- codes CONSTANT mark_ack : byte := "11111111"; CONSTANT mark_nack : byte := "00000000"; --~ FUNCTION uReg_read(uBus : IN uBus_port; reg : IN INTEGER ) RETURN BOOLEAN; FUNCTION uReg_write(uBus : IN uBus_port; reg : IN INTEGER ) RETURN BOOLEAN; -- ----------------------------------------------------------------------- -- op codes -- ----------------------------------------------------------------------- -- -- The opcodes' fields are defined in the instruction register as follows: -- 7 6 5 4 3 2 1 0 -- |---|---|---|---|---|---|---|---| -- | | | | | | | | | -- |---|---|---|---|---|---|---|---| -- |LIT| TYPE | STACK | GROUP | -- |---|-------|-------|-----------| -- -- ----------------------------------------------------------------------- -- TYPE -- ----------------------------------------------------------------------- -- Code Name Action -- 00 BRA Branches, Calls and Returns -- 01 ALU Binary and Unary Operators -- 10 MEM Data-Memory and Register access -- 11 USR Unused by core, free for user extensions -- ----------------------------------------------------------------------- -- STACK -- ----------------------------------------------------------------------- -- Code Name Action -- 00 NONE Type dependent -- 01 POP Stack->NOS->TOS -- 10 PUSH TOS->NOS->Stack -- 11 BOTH Type dependent -- ------------------------------------------------------------------- -- Opcodes by Group -- ------------------------------------------------------------------- -- BRA NONE POP PUSH BOTH -- 0 00 nop -0 branch +0 dup -0 drop -- 1 00 rot ?-0 ?dup-branch 2c ?0 ?dup -0 st_set -- 2 00 -rot --0 s-branch 2c +0 unpack -0 pack -- 3 00 less? --0 ns-branch 2c +0 under -0 multl -- 4 --0 z-branch 2c +0 tuck -? z-exit -- 5 0- back --0 nz-branch 2c +0 ovfl? -? nz-exit -- 6 0- rdrop -0 no-branch +0 carry? -? tor-branch -- 7 0- exit -0 nc-branch +0 I -- iret -- ------------------------------------------------------------------- -- ALU NONE POP PUSH BOTH -- 0 00 umult -0 + +0 2dup + 00 invert -- 1 00 smult -0 +c +0 2dup +c -- 2 00 div -0 - +0 2dup - 00 dshift -- 3 00 time? -0 swap- +0 2dup swap- 00 dashift -- 4 -0 sdivl -0 and +0 2dup and 00 shift -- 5 -0 udivl -0 or +0 2dup or 00 ashift -- 6 0-0 +st 2c -0 xor +0 2dup xor 00 0= -- 7 00 swap -0 nip +0 over 00 0< -- ------------------------------------------------------------------- -- MEM NONE POP PUSH BOTH -- 0 -0 status! -0 ST +0 LD +0 status@ -- 1 -+ forward -0 1 + ST +0 1 + LD +0 r@ -- 2 -0 lst -0 2 + ST +0 2 + LD +0 lld -- 3 -+ >r -0 3 + ST +0 3 + LD +- r> -- 4 -0 rsp! -0 4 - ST +0 4 - LD +0 rsp@ -- 5 -0 dsp! -0 3 - ST +0 3 - LD +0 dsp@ -- 6 -0 tst -0 2 - ST +0 2 - LD +0 tld -- 7 -+ call -0 1 - ST +0 1 - LD 00 signed -- ------------------------------------------------------------------- -- USR NONE POP PUSH BOTH -- 0 00 udivs 00 logs -- 1 ++ int 00 sqrts -- 2 0+ exc 00 norm -- 3 0? ?ovfl -- 4 0+ break -- 5 0+ data! -- 6 00 sdivs -0 fmult -- 7 -0 float +0 integ -- ------------------------------------------------------------------ --~-- -- BRA NONE CONSTANT op_NOP : byte := "00000000"; CONSTANT op_ROT : byte := "00000001"; CONSTANT op_NROT : byte := "00000010"; CONSTANT op_LESSQ : byte := "00000011"; CONSTANT op_BACK : byte := "00000101"; CONSTANT op_RDROP : byte := "00000110"; CONSTANT op_EXIT : byte := "00000111"; -- BRA POP CONSTANT op_ALWAYS : byte := "00001000"; -- ELSE, REPEAT CONSTANT op_QZERO : byte := "00001001"; -- ?dup IF CONSTANT op_SIGN : byte := "00001010"; -- 0< 0= IF CONSTANT op_NSIGN : byte := "00001011"; -- 0< IF CONSTANT op_ZERO : byte := "00001100"; -- IF CONSTANT op_NZERO : byte := "00001101"; -- 0= IF CONSTANT op_NOVFL : byte := "00001110"; -- ovfl? IF CONSTANT op_NCARRY : byte := "00001111"; -- carry? IF -- BRA PUSH CONSTANT op_DUP : byte := "00010000"; CONSTANT op_QDUP : byte := "00010001"; CONSTANT op_UNPACK : byte := "00010010"; CONSTANT op_UNDER : byte := "00010011"; CONSTANT op_TUCK : byte := "00010100"; CONSTANT op_OVFLQ : byte := "00010101"; CONSTANT op_CARRYQ : byte := "00010110"; CONSTANT op_INDEX : byte := "00010111"; -- BRA BOTH CONSTANT op_DROP : byte := "00011000"; CONSTANT op_SSTAT : byte := "00011001"; CONSTANT op_PACK : byte := "00011010"; CONSTANT op_MULTL : byte := "00011011"; CONSTANT op_ZEXIT : byte := "00011100"; CONSTANT op_NZEXIT : byte := "00011101"; CONSTANT op_NEXT : byte := "00011110"; CONSTANT op_IRET : byte := "00011111"; -- ALU NONE CONSTANT op_UMULT : byte := "00100000"; CONSTANT op_SMULT : byte := "00100001"; CONSTANT op_DIV : byte := "00100010"; CONSTANT op_TIMEQ : byte := "00100011"; CONSTANT op_SDIVL : byte := "00100100"; CONSTANT op_UDIVL : byte := "00100101"; CONSTANT op_PST : byte := "00100110"; CONSTANT op_SWAP : byte := "00100111"; -- ALU POP CONSTANT op_ADD : byte := "00101000"; CONSTANT op_ADC : byte := "00101001"; CONSTANT op_SUB : byte := "00101010"; CONSTANT op_SSUB : byte := "00101011"; CONSTANT op_AND : byte := "00101100"; CONSTANT op_OR : byte := "00101101"; CONSTANT op_XOR : byte := "00101110"; CONSTANT op_NIP : byte := "00101111"; -- ALU PUSH CONSTANT op_PADD : byte := "00110000"; CONSTANT op_PADC : byte := "00110001"; CONSTANT op_PSUB : byte := "00110010"; CONSTANT op_PSSUB : byte := "00110011"; CONSTANT op_PAND : byte := "00110100"; CONSTANT op_POR : byte := "00110101"; CONSTANT op_PXOR : byte := "00110110"; CONSTANT op_OVER : byte := "00110111"; -- ALU BOTH CONSTANT op_NOT : byte := "00111000"; CONSTANT op_DSHIFT : byte := "00111010"; CONSTANT op_DASHIFT : byte := "00111011"; CONSTANT op_SHIFT : byte := "00111100"; CONSTANT op_ASHIFT : byte := "00111101"; CONSTANT op_ZEQU : byte := "00111110"; CONSTANT op_ZLESS : byte := "00111111"; -- MEM NONE CONSTANT op_WSTAT : byte := "01000000"; CONSTANT op_FWRD : byte := "01000001"; CONSTANT op_WLOCAL : byte := "01000010"; CONSTANT op_RPUSH : byte := "01000011"; CONSTANT op_WRSP : byte := "01000100"; CONSTANT op_WDSP : byte := "01000101"; CONSTANT op_WTASK : byte := "01000110"; CONSTANT op_CALL : byte := "01000111"; -- MEM POP CONSTANT op_STORE : byte := "01001000"; CONSTANT op_wST : byte := "01001011"; CONSTANT op_iST : byte := "01001100"; CONSTANT op_cST : byte := "01001101"; -- MEM PUSH CONSTANT op_LOAD : byte := "01010000"; CONSTANT op_wLD : byte := "01010011"; CONSTANT op_iLD : byte := "01010100"; CONSTANT op_cLD : byte := "01010101"; -- MEM BOTH CONSTANT op_RSTAT : byte := "01011000"; CONSTANT op_RTOR : byte := "01011001"; CONSTANT op_RLOCAL : byte := "01011010"; CONSTANT op_RPOP : byte := "01011011"; CONSTANT op_RRSP : byte := "01011100"; CONSTANT op_RDSP : byte := "01011101"; CONSTANT op_RTASK : byte := "01011110"; CONSTANT op_SIGNED : byte := "01011111"; -- USR NONE CONSTANT op_USR : byte := "01100000"; CONSTANT op_UDIVS : byte := "01100000"; CONSTANT op_INT : byte := "01100001"; CONSTANT op_EXC : byte := "01100010"; CONSTANT op_QOVFL : byte := "01100011"; CONSTANT op_BREAK : byte := "01100100"; CONSTANT op_DATA : byte := "01100101"; CONSTANT op_ADDR : byte := "01100110"; -- trap target, not an instruction CONSTANT op_SDIVS : byte := "01100110"; -- instruction shares code with trap target -- USR POP CONSTANT op_FMULT : byte := "01101110"; -- fractional halfsigned multiply CONSTANT op_FLOAT : byte := "01101111"; -- integer > float -- USR PUSH CONSTANT op_INTEG : byte := "01110111"; -- float > integer -- USR BOTH CONSTANT op_LOGS : byte := "01111000"; CONSTANT op_SQRTS : byte := "01111001"; CONSTANT op_NORM : byte := "01111010"; --Forth END constants; PACKAGE BODY constants IS ---------------------------------------------------------------- -- uReg_read -- returns true flag if register is addressed by reading uCore ---------------------------------------------------------------- FUNCTION uReg_read(uBus : IN uBus_port; reg : IN INTEGER ) RETURN BOOLEAN IS VARIABLE temp : BOOLEAN; VARIABLE reg_addr : reg_bus; BEGIN reg_addr := to_vec(reg, reg_addr_width); IF uBus.reg_addr = reg_addr AND uBus.write = '0' THEN temp := true; ELSE temp := false; END IF; RETURN temp; END; ---------------------------------------------------------------- -- uReg_write -- returns true flag if register is addressed by writing uCore ---------------------------------------------------------------- FUNCTION uReg_write(uBus : IN uBus_port; reg : IN INTEGER ) RETURN BOOLEAN IS VARIABLE temp : BOOLEAN; VARIABLE reg_addr : reg_bus; BEGIN reg_addr := to_vec(reg, reg_addr_width); IF uBus.reg_addr = reg_addr AND uBus.write = '1' THEN temp := true; ELSE temp := false; END IF; RETURN temp; END; END constants;