head 1.1; branch 1.1.1; access ; symbols start':1.1.1.1 cd16:1.1.1; locks ; strict; comment @# @; 1.1 date 2003.08.15.17.26.02; author beckert; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 2003.08.15.17.26.02; author beckert; state Exp; branches ; next ; desc @@ 1.1 log @Initial revision @ text @ CD16 rev 3
-- \ Dual language RTL model of the CD16 CPU.
-- \ Author: Brad Eckert
-- \ revision: 3

-- \ Even free stuff needs lawyer repellant:

-- \ ----------------------------------------------------------------------------------------------------------- \
-- \ Copyright (C) 2003 Brad Eckert   brad@@tinyboot.com                                                          \
-- \                                                                                                             \
-- \ This source file may be used and distributed without restriction provided that this copyright statement is  \
-- \ not removed from the file and that any derivative work contains the original copyright notice and the       \
-- \ associated disclaimer.                                                                                      \
-- \                                                                                                             \
-- \    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    \
-- \ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT     \
-- \ SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR     \ 
-- \ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF  \
-- \ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  \
-- \ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   \
-- \ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                        \
-- \ ----------------------------------------------------------------------------------------------------------- \

-- \ This model can be simulated with either a 32-bit ANS Forth or a VHDL simulator. The code to the left of '--'
-- \ is intended to be ignored by the Forth interpreter. The code to the right is ignored by the VHDL tool.
-- \ Structures are expressed side by side in both languages so as to comment each other. The Forth model
-- \ represents bits and vectors in a less rigorous way, so it can simulate much faster than the VHDL model.

-- \ 8pt Courier allows 115 columns on Letter paper. Let VHDL comments begin at column 49, leaving 67 columns
-- \ for Forth. A screen resolution of 1024x768 or better is desirable when editing or browsing this file.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.CD16pkg.all;

entity CD16 is
   port(reset, clk: in std_logic;               -- \ reset the CPU, master clock
        hold:  in std_logic;                    -- ' undef in: hold  \ insert wait states
        int:   in std_logic_vector(7 downto 1); -- ' undef in: int   \ interrupt trigger
        ya,yb: in  cell;                        -- \ Data from Stack DPRAM (already defined)
        ia,ib: out cell;                        -- \ Data to Stack DPRAM
        aa,ab: out std_logic_vector(spwidth-1 downto 0); -- \ Stack DPRAM address
        wa,wb: out std_logic;                   -- \ Stack DPRAM write enables
        ra,rb: out std_logic;                   -- \ Stack DPRAM read enables
        py: out cell;                           -- \ Data to program space
        pi: in  cell;                           -- ' undef in: pi    \ Data from program space
        pa: out cell;                           -- \ Program space address
        pbank: out std_logic_vector(5 downto 0); -- \ Program bank select
        wp: out std_logic;                      -- \ write to program memory, sync write
        dy: out cell;                           -- \ Data to data space
        di: in  cell;                           -- ' undef in: di    \ Data from data space
        da: out cell;                           -- \ Data space address
        wd: out std_logic;                      -- \ write to data memory, sync write
        rd: out std_logic;                      -- \ data mem read-enable, sync read
        CPA: in cell;                           -- ' undef in: CPA
        CPO: in cell;                           -- ' undef in: CPO
        CPctrl: out std_logic_vector(6 downto 0); -- w: CPctl
        t_P,t_IR,t_W: out cell;
        t_SP,t_RP: out std_logic_vector(spwidth-1 downto 0); -- \ debugging vectors
        t_cv: out std_logic_vector(1 downto 0));
end CD16;
        -- n 2^n          mask &sign   ( sign bit mask        )  -1 &sign 1- CONSTANT maxint
        -- n 3 + 2^n      mask &carry  ( ALU carry-out mask   )  n 3 - 2^n 1- mask &brdisp
        -- n 1+ 2^n 1-    mask &cell   ( cell-wide mask       )  n 4 - 2^n CONSTANT brsign
        -- n 1+ 2^n       mask &sign+1 ( W register sign bit  )  n 2 + 2^n 1- mask &cell+1
architecture behavioral of CD16 is
    constant zro: std_logic_vector(n downto 1) := (others=>'0'); --     \ 0
    -- \ registers may be changed to arrays for instant context switching
    signal SP,RP: std_logic_vector(spwidth-1 downto 0); -- r: SP  r: RP \ stack pointers
    signal P:  cell;                            -- r: P                 \ program counter
    signal IR: cell;                            -- r: IR                \ instruction reg
    signal W:  std_logic_vector(n+1 downto 0);  -- r: W                 \ W reg
    signal cf,ov: std_logic;                    -- r: cf   r: ov        \ carry flag, overflow flag
    signal sleep: std_logic;                    -- r: sleep             \ sleep until interrupt
    signal reps:  std_logic_vector(4 downto 0); -- r: reps              \ REP counter
    signal bank:  std_logic_vector(5 downto 0); -- r: bank              \ Program bank select
    signal resetd: std_logic;                   -- r: resetd            \ buffered reset line
    -- \ interrupt logic
    signal drowsy: std_logic;                   -- w: drowsy            \ trigger sleep mode
    signal iack: std_logic;                     -- w: iack              \ interrupt just acknowledged
    signal intd, IRQpend: std_logic_vector (7 downto 1); -- r: intd  r: IRQpend
    signal ipl:           std_logic_vector (2 downto 0);
    -- \ stack addressing logic
    signal wrena, wrenb: std_logic;             -- w: wrena w: wrenb    \ stack memory write enable
    signal rdena, rdenb: std_logic;             -- w: rdena w: rdenb    \ stack memory read enable
    signal ssel: std_logic;                     -- w: ssel              \ select 0=SP, 1=RP (addresses A)
    signal predec: std_logic;                   -- w: predec            \ predec selected stack pointer
    signal postinc: std_logic;                  -- w: postinc           \ postinc selected stack pointer
    signal xbump: std_logic;                    -- w: xbump             \ postinc by signed offset
    signal xen, selcon: std_logic;              --                      \ latch enable SP/RP, select +/- 1
    signal yax: std_logic;                      -- w: yax               \ route YA to XP if enabled
    signal rex: std_logic;                      -- w: rex               \ enable extended Rstack addressing
    signal xpxs: std_logic;
    signal xpsx:    std_logic_vector(spwidth-7 downto 0);               -- \ sign extension for SP displacement
    signal cons1:   std_logic_vector(spwidth-2 downto 0);               -- \ sign extension for constant +/- 1
    signal XP,spin: std_logic_vector(spwidth-1 downto 0);               -- \ selected ptr for A
    signal xfb, offa, para, xpx: std_logic_vector(spwidth-1 downto 0);  -- \ inter-mux busses
    type iaselect is (ia_p, ia_w, ia_xp, ia_c, ia_uo, ia_pi, ia_di);    -- $ ia_p  $ ia_w $ ia_xp $ ia_c $ ia_uo
    signal iasel: iaselect;                     -- w: iasel                $ ia_pi $ ia_di
    type ibselect is (ib_uo, ib_cp, ib_ya);                             -- $ ib_uo $ ib_cp $ ib_ya
    signal ibsel: ibselect;                     -- w: ibsel
    signal div: std_logic;                      -- w: div               \ enable divider latch
    -- \ P register
    signal pin, brdis: cell;                    --                      \ P in, signed branch displacement
    type pselect is (p_bump, p_ir, p_ya);                               -- $ p_bump $ p_ir $ p_ya
    signal psel: pselect;                       -- w: psel              \ src = P+1, P+IR, IR, YA
    signal bran: std_logic;                     -- w: bran              \ 1: P adder uses displacement brdis
    signal stall: std_logic;                    -- w: stall             \ 1: don't bump PC
    signal repen, repeating: std_logic;         -- w: repen             \ 1: load REP counter
    signal banken: std_logic;                   -- w: banken            \ 1: load BANK register
    -- \ W register
    signal win: std_logic_vector(n+1 downto 0); --                      \ pending W (if wen=1)
    signal wm: std_logic_vector(1 downto 0);    -- w: wm                \ W source
    signal wen: std_logic;                      -- w: wen               \ latch enable W
    -- \ ALU inputs A and B                                             \ ALU inputs A and B
    signal ub,ua,uo,uol,iacond: cell;
    signal ubm: std_logic_vector(3 downto 0);   -- w: ubm               \ B = shiftop(YB,ubm)
    signal uam: std_logic;                      -- w: uam               \ A = const, YA1
    signal uas: std_logic;                      -- w: uas               \ YA1 = YA, YA>>8
    signal mul, uasel, ubc, nz: std_logic;      -- w: mul               \ input A is in multiplier mode
    signal sub: std_logic;                      -- w: sub               \ force ALU carry in to '1'
    signal aluop: std_logic_vector(2 downto 0); -- w: aluop             \ +, C+, +C, C+C, A, A&B, A!B, A^B
    signal uoa: std_logic_vector(n+3 downto 0); -- \ adder result with carry in and carry out
    signal acsx: std_logic_vector(n downto 2);  -- \ 14-bit A constant sign extension
    signal acon: std_logic_vector(1 downto 0);  -- w: acon              \ A constant = 0, 1, -2, -1
    signal ya1, aconst: cell;                   --                      \ A possible inputs
    -- \ carry flag
    signal cin, uci: std_logic;
    signal cm: std_logic_vector(1 downto 0);    -- w: cm                \ src = cf, carry(A+B), YB(n), YB(0)
    signal cen: std_logic;                      -- w: cen               \ carry latch enable
    -- \ IR and branch
    signal flush: std_logic;                    -- w: flush             \ discard data on the instruction bus
    signal flushIR: cell;                       -- w: flushIR           \ the pending "nop"
    signal condition: std_logic;                -- \ condition(IR11:IR8)
    signal dissx: std_logic_vector(n downto 12); -- \ sign extension for branch displacement
    -- \ Program memory
    signal pasel: std_logic;                    -- w: pasel             \ program address
    signal pw: std_logic;                       -- w: pw                \ prog write enable
    -- \ Data memory
    type aselect is (a_cp, a_yb, a_pi);                                 -- $ a_cp $ a_yb $ a_pi
    signal dasel: aselect;                      -- w: dasel             \ select data memory address
    signal dw, drd: std_logic;                  -- w: dw  w: drd        \ data write enable, read enable

begin
 ipl <= "001" when IRQpend(1) = '1' else        -- \ interrupt priority encoder: level 1 is highest priority
        "010" when IRQpend(2) = '1' else        -- : ipl  ( -- n ) IRQpend @@@@ DUP IF                         \ {2}
        "011" when IRQpend(3) = '1' else        --     DUP  0F0 AND 0<> 4 AND
        "100" when IRQpend(4) = '1' else        --     OVER 0CC AND 0<> 2 AND +
        "101" when IRQpend(5) = '1' else        --     SWAP 0AA AND 0<> 1 AND +
        "110" when IRQpend(6) = '1' else        --   THEN ;
        "111" when IRQpend(7) = '1' else "000";

        nz <= W(16) or W(15) or W(14) or W(13)  -- : nz      ( -- bit )    W @@@@ -2 AND 0<> 1 AND ;   \ '1' if W<>0
           or W(12) or W(11) or W(10) or W(9)   -- : w(n+1)  ( -- bit )    W @@@@ &sign+1 0<> 1 AND ;    \ sign of W
           or  W(8) or  W(7) or  W(6) or W(5)   -- : w(n)    ( -- bit )    W @@@@ &sign 0<> 1 AND ;    \ sign of W/2
           or  W(4) or  W(3) or  W(2) or W(1);  -- : cf@@     ( -- bit )    cf @@@@ 1 AND ;             \ carry latch
                                                -- : inv     ( bit -- !bit ) INVERT 1 AND ;             \ flip bit
                                                -- : hialu   ( n bit -- n' ) n 2 + lshift OR ;      \ adder hi bit
                                                -- : bit?    ( mask -- bit ) AND 0<> 1 AND ;
        repeating <= '0' when reps="00000" else '1';
                                                -- : repeating ( -- f )  reps @@@@ 0<> 1 AND ;
        xen <= predec or postinc or xbump;      -- : xen     ( -- f )    predec @@ postinc @@ xbump @@ OR OR ;
        XP <= RP when ssel='1' else SP;         -- : XP      ( -- ptr )  ssel @@ IF RP ELSE SP THEN @@@@ ;

        xpsx <= (others => (xbump and IR(9)));  -- : xpsx    ( -- sext ) xbump @@ 0<> IR @@@@ 200 AND 0<> AND ;

        para <= xpsx & IR(9 downto 4) when rex='1' -- : para ( -- n )    IR @@@@ 4 RSHIFT  rex @@
                else zro(spwidth downto 5)&IR(7 downto 4); -- IF 03F AND xpsx -40 AND OR ELSE 0F AND THEN &sa ;
        cons1 <= (others => predec);
        selcon <= (postinc and (not xbump)) or predec;
        offa <=  cons1&'1' when selcon='1'      -- : offa    ( -- n )    postinc @@ xbump @@ 0= AND predec @@ OR
                else para;                      --           IF predec @@ IF -1 ELSE 1 THEN &sa ELSE para THEN ;

        xfb  <= (XP + offa);                    -- : xfb     ( -- n )    XP offa + &sa ;
        xpxs <= IR(7) and (not xen) and (not rex); -- : xpxs ( -- f )    IR @@@@ 80 bit?  xen 0= AND  rex @@ 0= AND ;
        xpx  <= zro(spwidth downto 4)&IR(6 downto 4) --
                      when xpxs='1' else XP;    -- : xpx     ( --f )  xpxs IF IR @@@@ 4 RSHIFT 7 AND ELSE XP THEN ;

        aa   <= zro(spwidth downto 5)&'1'&(not ipl) when iack='1' -- :noname ( -- n ) iack @@ IF ipl 7 XOR 8 OR 
                else xfb when (postinc='0' and xpxs='0')  -- ELSE postinc @@ 0= xpxs 0= and
                else xpx;                       --           IF xfb ELSE xpx THEN THEN ;                is aa

        ab   <= zro(spwidth downto 4)&IR(2 downto 0)
                   when IR(3)='1'               -- :noname   ( -- n )    IR @@@@  DUP 8 AND     \ address of B param
                else (SP + IR(2 downto 0));     --           IF 7 AND ELSE 7 AND SP @@@@ + THEN ;         is ab
                                                -- : ybn@@    ( -- bit )  yb &sign 0<> 1 AND ;     \ sign bit of YB
        dissx <= (others=>IR(n-4));             -- : dissx   ( -- n ) IR @@@@ brsign AND 0<> -1 &brdisp INVERT AND ;
        brdis <= dissx&IR(n-4 downto 0)         -- : brdis   ( -- disp ) bran @@ IF IR @@@@ &brdisp dissx OR
                when bran='1'                   --          ELSE stall @@ resetd @@@@ or repeating or 0= 1 AND THEN ;
                else zro&(not(stall or resetd or repeating));
                                                -- : yan@@    ( -- bit )  ya &sign 0<> 1 AND ;     \ sign bit of YA
        with psel select                        -- : pin     ( -- n ) psel @@ CASE                        \ P input
        pin  <= P + brdis     when p_bump,      --           p_bump OF P @@@@ brdis +             ENDOF
                IR(n-1 downto 0) & '0' when p_ir, --         p_ir   OF IR @@@@ maxint AND 2*      ENDOF
                YA            when p_ya;        --           p_ya   OF ya                       ENDOF
                                                --           ABORT" Invalid PSEL" ENDCASE ;
        with ubm(1 downto 0) select             -- : ubc     ( -- bit ) ubm @@ 3 and CASE     \ shifter carry input
        ubc  <= '0'           when "00",        --           0 OF 0                             ENDOF
                cf            when "01",        --           1 OF cf@@                           ENDOF
                W(n+1)        when "10",        --           2 OF w(n+1)                        ENDOF
                YB(n)         when others;      --           3 OF ybn@@                          ENDOF
                                                --           ENDCASE ;
        with ubm(3 downto 2) select             -- : ub      ( -- n ) ubm @@ 2 RSHIFT CASE          \ ALU 'A' input
        ub   <= YB when "00",                   --           0 OF YB                            ENDOF
                (not YB) when "01",             --           1 OF YB INVERT &cell               ENDOF
                YB(n-1 downto 0) & ubc when "10", --         2 OF YB 2* ubc OR &cell            ENDOF
                ubc & YB(n downto 1) when others; --         3 OF YB 1 RSHIFT ubc n LSHIFT OR   ENDOF
                                                --           ABORT" Invalid UBM" ENDCASE ;
        uasel <= W(n) when mul='1' else uam;    -- : uasel   ( -- bit ) mul @@ IF w(n) ELSE uam @@ THEN ;
        acsx <= (others=>(acon(1) and acon(0))); -- CREATE aconsts 0 , 1 , 2 , -1 ,
        aconst <= acsx & acon;                  -- : aconst  ( -- n ) acon @@ 3 AND CELLS aconsts + @@ &cell ;
                                                -- : swhalf  ( n -- n' ) 2 n 2/ LSHIFT DUP >R /MOD SWAP R> * + ;
        ya1  <= YA((n-1)/2 downto 0)            -- : ya1     ( -- n ) YA  uas @@              \ swap hi & lo halves
              & YA(n downto (n+1)/2)            --           IF swhalf THEN ;
                when uas='1' else YA;           -- : ua      ( -- n ) uasel                        \ ALU 'B' input
        ua   <= ya1 when uasel='1' else aconst; --           IF ya1 ELSE aconst THEN ;
        with aluop(1 downto 0) select           -- : uol     ( -- n ) aluop @@ 3 AND CASE       \ logic part of ALU
        uol  <= ub              when "00",      --           0 OF ub                            ENDOF
                (ub and ua)     when "01",      --           1 OF ub ua AND                     ENDOF
                (ub or  ua)     when "10",      --           2 OF ub ua OR                      ENDOF
                (ub xor ua)     when others;    --           3 OF ub ua XOR                     ENDOF
                                                --           ENDCASE ;
        uci  <= (cf and aluop(1) and aluop(0))  -- : uci     ( -- bit ) aluop @@ 3 AND 3 = cf@@ AND sub @@ OR ;
                or sub;
        uoa  <= (('0'&div&ub&'1')               -- : uoa     ( -- n ) ub 2* 1 + div @@ hialu    \ adder part of ALU
             + ('0'&((not div) or cf)&ua&uci)); --           ua 2* uci +
                                                --           div @@ inv cf@@ OR hialu + ;
        uo   <= uol when aluop(2)='1'           -- : uo      ( -- n ) aluop @@ 4 AND IF uol         \ output of ALU
                else uoa(n+1 downto 1);         --                    ELSE uoa 2/ &cell THEN ;
        with cm select                          -- : cin     ( -- n ) cm @@ CASE                         \ cf input
        cin  <= '0'             when "00",      --           0 OF 0                             ENDOF
                uoa(n+3)        when "01",      --           1 OF uoa &carry 0<> 1 AND          ENDOF
                YB(n)           when "10",      --           2 OF ybn@@                          ENDOF
                YB(0)           when others;    --           3 OF YB 1 AND                      ENDOF
                                                --           ABORT" Invalid CM" ENDCASE ;
        with IR(11 downto 9) select
        condition <=                            -- : condition ( -- f ) IR @@@@ 9 RSHIFT 7 AND CASE
            IR(8) xor '0'               when "000",     --   0 OF 0                             ENDOF
            IR(8) xor (cf nand nz)      when "001",     --   1 OF cf@@ nz and inv                ENDOF        \ {1}
            IR(8) xor cf                when "010",     --   2 OF cf@@                           ENDOF
            IR(8) xor (not nz)          when "011",     --   3 OF nz inv                        ENDOF
            IR(8) xor ov                when "100",     --   4 OF ov @@@@                         ENDOF
            IR(8) xor W(n+1)            when "101",     --   5 OF w(n+1)                        ENDOF
            IR(8) xor ((W(n+1) xor ov)) when "110",     --   6 OF ov @@@@ w(n+1) xor              ENDOF
            IR(8) xor ((W(n+1) xor ov)                  --   7 OF ov @@@@ w(n+1) xor nz inv or    ENDOF
                  or (not nz))          when others;    --   ENDCASE IR @@@@ 100 AND 0<> XOR 1 AND ;

        iacond <= (others => condition);        -- : iacond  ( -- n ) condition 0<> &cell ;
        spin <= YA(spwidth-1 downto 0)          -- : spin    ( -- n ) yax @@ IF YA ELSE xfb THEN ;     \ pending XP
                   when yax='1' else xfb;

        with dasel select                       -- : da      ( -- n ) dasel @@ CASE
        da   <= PI              when a_pi,      --           a_pi  OF PI                        ENDOF
                CPA             when a_cp,      --           a_cp  OF CPA                       ENDOF
                YB              when a_yb;      --           a_yb  OF YB                        ENDOF
                                                --           ABORT" Invalid DASEL" ENDCASE ;
        pa   <= YB when pasel='1' else pin;     -- : pa      ( -- n ) pasel @@ IF YB else pin THEN ;
       pbank <= bank when pasel='1'             -- : pbank   ( -- n ) pasel @@ IF bank @@@@ else 0 THEN ;       \ {3}
                else (others=>'0');             -- \ Program memory read is banked. Program is limited to bank 0.

        with iasel select                       -- :noname   ( -- n ) iasel @@ CASE                 \ DPRAM A input
        ia   <= PI              when ia_pi,     --           ia_pi OF PI                        ENDOF
                DI              when ia_di,     --           ia_di OF DI                        ENDOF
                uo              when ia_uo,     --           ia_uo OF uo                        ENDOF
                iacond          when ia_c,      --           ia_c  OF iacond                    ENDOF
       zro(n downto spwidth)&XP when ia_xp,     --           ia_xp OF XP  ( unsigned )          ENDOF
                W(n+1 downto 1) when ia_w,      --           ia_w  OF W @@@@ 1 RSHIFT             ENDOF
                P               when ia_p;      --           ia_p  OF P @@@@                      ENDOF
                                                --           ABORT" Invalid IASEL" ENDCASE ;            is ia
        with ibsel select                       -- :noname   ( -- n ) ibsel @@ CASE                 \ DPRAM B input
        ib   <= uo              when ib_uo,     --           ib_uo OF uo                        ENDOF
                CPO             when ib_cp,     --           ib_cp OF CPO                       ENDOF
                YA              when ib_ya;     --           ib_ya OF YA                        ENDOF
                                                --           ABORT" Invalid IBSEL" ENDCASE ;            is ib
        with wm select                          -- : win     ( -- n )    wm @@ CASE                       \ W input
        win  <= uo & '0' when "00",             --           0 OF uo 2*                         ENDOF
                '0' & uo when "01",             --           1 OF uo                            ENDOF
                (W(n downto 0) + cf) & '0'   when "10",   -- 2 OF W @@@@ cf@@ + 2*                 ENDOF
                (W(n downto 0) + cf) & YB(n) when others; -- 3 OF W @@@@ cf@@ + 2* ybn@@ +          ENDOF
                                                --           ABORT" Invalid WM" ENDCASE &cell+1 ;

        dy   <= YA;                             -- : dy      ( -- n ) YA ;
        wb   <= (div and uoa(n+3)) or wrenb;    -- :noname   ( -- bit ) uoa &carry 0<>
                                                --           div @@ AND wrenb @@ OR ;                     is wb
        wa   <= wrena;                          -- :noname   ( -- bit ) wrena @@ ;                       is wa
        ra   <= rdena;                          -- :noname   ( -- bit ) rdena @@ ;                       is ra
        rb   <= rdenb;                          -- :noname   ( -- bit ) rdenb @@ ;                       is rb
        py   <= YA;                             -- : py      ( -- n ) ya ;
        wp   <= pw;                             -- : wp      ( -- n ) pw @@ ;
        wd   <= dw;                             -- : wd      ( -- n ) dw @@ ;
        rd   <= drd;                            -- : rd      ( -- n ) drd @@ ;
                                                -- : CPctrl  ( -- n ) CPctl @@ ;
                                                -- DEFER opcodes DEFER miscops
    decode: process(IR,condition,ipl) begin     -- : getopcd ( -- op )
        rdena <= '0';  rdenb <= '0';            -- 0 rdena !  0 rdenb !
        uam<='0'; ubm<="0000"; wm<="00";        -- 0 uam !  0 ubm !  0 wm !    \ default wire settings
        aluop<="000"; rex<='0'; acon<="00";     -- 0 aluop ! 0 acon ! 0 rex !
        predec<='0'; postinc<='0';              -- 0 predec ! 0 postinc !
        wrena<='0'; wrenb<='0';                 -- 0 wrena ! 0 wrenb !
        flush<='0'; flushIR<=(others=>'0');     -- 0 flush ! 0 flushIR !
        pasel<='0'; pw<='0';                    -- 0 pasel ! 0 pw !
        dasel<=a_yb; dw<='0';                   -- a_yb dasel ! 0 dw !
        psel<=p_bump; banken<='0';              -- p_bump psel ! 0 banken !
        iasel<=ia_p; ibsel<=ib_uo;              -- ia_p iasel ! ib_uo ibsel !
        xbump<='0'; yax<='0'; drd<='0';         -- 0 xbump ! 0 yax ! 0 drd !
        div<='0'; mul<='0'; stall<='0';         -- 0 div ! 0 mul ! 0 stall !
        bran<='0'; sub<='0';                    -- 0 bran ! 0 sub !
        ssel<='0'; wen<='0'; repen<='0';        -- 0 ssel ! 0 wen ! 0 repen !
        cm<="00";  cen<='0'; uas<='0';          -- 0 cm ! 0 cen ! 0 uas !
        iack<='0';  drowsy<='0';                -- 0 iack ! 0 drowsy !
        CPctrl<='0'&IR(11 downto 6);            -- IR @@@@ 6 RSHIFT 3F AND CPctl !
                                                -- IR @@@@ n 3 - RSHIFT 7 AND ; \ 8 main instruction types
        if IR(n)='1' then                       -- : CPUdecode ( -- ) getopcd IR @@@@ &sign
                psel <= p_ir;                   -- IF   p_ir psel !  DROP    \ CALL: load new P
                ssel <= '1';                    --      1 ssel !             \ select RP
                predec <= '1';  wrena <= '1';   --      1 predec ! 1 wrena ! \ push at next clock
                flush <= '1';                   --      1 flush !            \ ignore next instruction
        else                                    -- ELSE CELLS opcodes + @@ EXECUTE process
            case IR(n-1 downto n-3) is          -- THEN      ;
                when "000" =>                   -- \ MISC                                      0000 cccc aaaa Sooo
                    ssel <= IR(3);              -- : op0 IR @@@@ 8 bit? ssel !                 \ 0000 --aa aaaa Sooo
                    case IR(2 downto 0) is      --      IR @@@@ 7 AND CELLS miscops + @@ EXECUTE ;
                        when "000" => flush<=condition; -- : mo0 condition flush !           \ 0000 cccc --p- Z000
                                      drowsy<=IR(3);    --       IR @@@@ 08 bit? drowsy !            \ sleep pending
                                      postinc<=IR(5);   --       IR @@@@ 20 bit? postinc ! ;
                        when "001" => psel <= p_ya;     -- : mo1 p_ya psel ! 
                                      rdena <= '1';     --       1 rdena !
                                      if (ipl /= "000") then --  ipl                         \ 0000 -f-- ---- s001
                                           iack<='1';   --       IF   1 iack !                   \ acknowledge irq
                                      else postinc<='1'; --      ELSE 1 postinc !                   \ RET and RETD
                                      end if;           --       THEN
                                      flush <= IR(10);  --       IR @@@@ 400 bit? flush ! ;
                        when "010" => yax   <= IR(8);   -- : mo2 IR @@@@ 100 bit? yax !        \ 0000 dfwy aaaa s010
                                      wrena <= IR(9);   --       IR @@@@ 200 bit? wrena !
                                      stall <= IR(10);  --       IR @@@@ 400 bit? stall !
                                      flush <= IR(10);  --       IR @@@@ 400 bit? flush !
                                      rdena <= '1';     --       1 rdena !
                                      if IR(11)='1' then   --    IR @@@@ 800 bit?
                                           iasel <= ia_di; --    IF   ia_di iasel !
                                      else iasel <= ia_pi; --    ELSE ia_pi iasel !
                                      end if;              --    THEN ;
                        when "011" => iasel <= ia_c;    -- : mo3 ia_c iasel !                \ 0000 cccc aaaa s011
                                      wrena <= '1';     --       1 wrena ! ;
                        when "100" => postinc<='1';     -- : mo4 1 postinc !                 \ 0000 r-aa aaaa s100
                                      xbump<='1';       --       1 xbump !               \ latch XP = XP + IR[9:4]
                                      rex<=IR(11);      --       IR @@@@ 800 bit? rex ! ;
                        when "101" => iasel <= ia_w;    -- : mo5 ia_w iasel !                \ 0000 rpx- aaaa s101
                                      rex   <= IR(11);  --       IR @@@@ 800 bit? rex !                \ IA(ext) = W
                                      predec <= IR(10); --       IR @@@@ 400 bit? predec !
                                      if IR(9)='1' then iasel <= ia_xp;  --                         \ IA(ext) = XP
                                      end if;           --       IR @@@@ 200 bit? if ia_xp iasel ! then
                                      wrena <= '1';     --       1 wrena ! ;
                        when "110" => flush <= '1';     -- : mo6 1 flush !  1 wrena !          \ IA(ext) = literal
                                      wrena <= '1';     --       IR @@@@ 400 bit?                   \ rp-- aaaa s110
                                      iasel <= ia_pi;   --       ia_pi iasel !
                                      rdena <= '1';     --       1 rdena !
                                      if IR(10)='1' then     --  IF IR @@@@ 200 bit?
                                          if IR(9)='1' then  --       IF  1 drd !
                                              dasel <= a_pi; --           a_pi dasel !
                                              wrena <= '0';  --           0 wrena !
                                              if IR(8)='1' then   --      IR @@@@ 100 bit?
                                                   dw <= '1';     --      IF   1 dw !
                                              else flushIR <= "00001010" & IR(7 downto 3) & "010";
                                                   drd <= '1';    --      ELSE 1 drd !         \ mem read
                                                                  --           IR @@@@ 00F8 AND 0A02 OR flushIR !
                                              end if;       --            THEN
                                          end if;           --        THEN
                                          predec<=IR(11);   --        IR @@@@ 800 bit? predec !
                                      else rex <= IR(11);   --   ELSE IR @@@@ 800 bit? rex !
                                      end if;           --       THEN ;
                        when others => iasel <= ia_p;   -- : mo7 ia_p iasel !                \ 0000 rfaa aaaa s111
                                      psel  <= p_ya;    --       p_ya psel !                      \ IA = P  P = YA
                                      rdena <= '1';     --       1 rdena !
                                      rex   <= IR(11);  --       IR @@@@ 800 bit? rex !
                                      flush <= IR(10);  --       IR @@@@ 400 bit? flush !
                                      wrena <= '1';     --       1 wrena ! ;       \ EXECUTE = 0000 0100 0000 1111
                    end case;                   -- CREATE mojmp ~ mo0 ~ mo1 ~ mo2 ~ mo3 ~ mo4 ~ mo5 ~ mo6 ~ mo7
                                                -- ' mojmp IS miscops
                when "001" =>                   -- \ BRANCH                                    0001 dddd dddd dddd
                    bran<='1'; flush<='1';      -- : op1 1 bran ! 1 flush ! ;
                when "010" =>                   -- \ COPROCESSOR                               0010 ???? ??pw bbbb
                    dasel <= a_cp;              -- : op2   a_cp dasel !                      \ data mem addr = CPA
                    ibsel <= ib_cp;             --      ib_cp ibsel !
                    wrenb <= IR(4);             --      IR @@@@ 10 bit? wrenb !
                    postinc <= IR(5);           --      IR @@@@ 20 bit? postinc !
                    CPctrl(6) <= '1';           --      CPctl @@ 40 OR CPctl !
                    rdenb <= '1';               --      1 rdenb !
                    drd   <= '1';               --      1 drd ! ;
                when "011" =>                   -- \ RSTACK                                    0011 ooaa aaaa bbbb
                    ssel <= '1';  rex <= '1';   -- : op3   1 rex !  1 ssel !               \ select RP = long addr
                    aluop<="100";               --      4 aluop !
                    case IR(11 downto 10) is    --      IR @@@@ 0C00 AND CASE
                        when "00" => iasel <= ia_uo; --    0000 OF ia_uo iasel !                          \ A := B
                                     aluop <= "100"; --            4 aluop !
                                     rdenb <= '1';   --            1 rdenb !
                                     wrena <= '1';   --            1 wrena !            ENDOF
                        when "01" => wrenb <= '1';   --    0400 OF 1 wrenb !                              \ B := A
                                     rdena <= '1';   --            1 rdena !
                                     ibsel <= ib_ya; --            ib_ya ibsel !        ENDOF
                        when "10" => iasel <= ia_uo; --    0800 OF ia_uo iasel !          \ push B to return stack
                                     aluop <= "100"; --            4 aluop !
                                     rdenb <= '1';   --            1 rdenb !
                                     predec <= '1';  --            1 predec !
                                     wrena<='1';     --            1 wrena !            ENDOF
                        when others => wrenb<='1';   --    0C00 OF 1 wrenb !             \ pop B from return stack
                                     rdena <= '1';   --            1 rdena !
                                     ibsel <= ib_ya; --            ib_ya ibsel !
                                     postinc <= '1'; --            1 postinc !          ENDOF
                    end case;                        -- ENDCASE ;
                when "100" =>                   -- \ ARITH                                     0100 duuu aaaa bbbb
                    aluop <= IR(10 downto 8);   -- : op4   IR @@@@ 8 RSHIFT 7 AND aluop ! \ 0 d = A + B
                    if  (IR(10 downto 8)="001") --      aluop @@ 1 =                     \ 1 d = A - B, save CF
                        then ubm<="0100"; sub<='1'; --  IF 4 ubm ! 1 sub !              \ 2 d = A + B, save CF
                        cm<= "01"; cen<='1';    --         1 cm !  1 cen !              \ 3 d = A + B + CF, saveCF
                    end if;                     --      THEN                            \ 4 d = B
                    if  (IR(10 downto 9)="01")  --      aluop @@ 6 AND 2 =               \ 5 d = A and B
                        then cm<= "01"; cen<='1';  --   IF 1 cm ! 1 cen !               \ 6 d = A or B
                    end if;                     --      THEN                            \ 7 d = A xor B
                    wen<='1';  iasel<=ia_uo;    --      1 wen !  ia_uo iasel !
                    if IR(11)='1' then          --      IR @@@@ 800 AND
                        wrena<='1';             --      IF   1 wrena !
                    end if;                     --      THEN
                    rdena <= '1'; rdenb <= '1'; --      1 rdena ! 1 rdenb !
                    uam<='1';                   --      1 uam ! ;
                when "101" =>                   -- \ SHIFT                                     0101 ssss aaaa bbbb
                    ubm <= IR(11 downto 8);     -- : op5   IR @@@@ 8 RSHIFT 0F AND ubm !
                    rdenb <= '1';               --      1 rdenb !
                    wrena <= '1';               --      1 wrena !                                \ A = shift_op(B)
                    if IR(11)='1' then          --      IR @@@@ 800 AND                            \   + constant
                        cm <= IR(11 downto 10); --      IF   ubm @@ 2 RSHIFT cm !
                        cen<='1';               --           1 cen !
                        rdena <= '1';           --           1 rdena !
                    else acon <= IR(9 downto 8); --     ELSE ubm @@ 3 AND acon !
                    end if;                     --      THEN
                    wen<='1';  iasel<=ia_uo;    --      1 wen !  ia_uo iasel ! ;                       \ copy to W
                when "110" =>                   -- \ MEMORY                                    0110 oodp aaaa bbbb
                    wrenb<= IR(8);              -- : op6 IR @@@@ 100 bit? wrenb !              \ post inc/dec if p=1
                    acon <= IR(9) & '1';        --      IR @@@@ 200 bit? 2* 1+ acon !              ( uo = YB +/- 1 )
                    rdenb <= '1';               --      1 rdenb !
                    if IR(11)='1' then          --   IR @@@@ 800 AND IF
                        rdena <= '1';           --      1 rdena !
                        if IR(10)='1' then      --      IR @@@@ 400 AND IF                        \ 11xx = Write D
                             dw<='1';           --           1 dw !
                        else pasel<='1'; pw<='1';    -- ELSE 1 pasel ! 1 pw !                   \ 10xx = Write P
                             stall<='1'; flush<='1'; --      1 stall ! 1 flush !
                        end if;                 --      THEN
                    else                        --   ELSE                                       \ Read Operation:
                        if IR(10)='1' then      --      IR @@@@ 400 AND IF
                             if IR(9 downto 8) /= "10" then
                                 wrena <= '1';  --           IR @@@@ 8 rshift 3 and 2 <>          \ 0110 = pre-read
                             end if;            --           IF 1 wrena ! THEN
                             iasel <= ia_di;    --           ia_di iasel !                      \ 01xx = Read D[b]
                             drd<='1';          --           1 drd !
                        else pasel<='1';        --      ELSE 1 pasel !                          \ 00xx = Read P[b]
                             flush<='1';        --           1 flush !
                             stall<='1';        --           1 stall !
                             if IR(9 downto 8) = "10" then   --                                 \ xx=01 postinc
                                 predec <= '1'; --           IR @@@@ 8 rshift 3 and 2 =           \ xx=11 postdec
                             end if;            --           IF 1 predec ! THEN                 \ 0010 = push P[b]
                             flushIR <= "00000110" & IR(7 downto 4) & "0010";
                                                --           IR @@@@ 00F0 AND 0602 OR flushIR !
                        end if;                 --      THEN 
                    end if;                     --   THEN ;
                when others =>                  -- \ MATH                                      0111 oooo aaaa bbbb
                    rdenb <= '1';               -- : op7 1 rdenb !
                    if IR(11)='1' then          --   IR @@@@ 800 AND IF                        \ W operation:
                        wm <= IR(9 downto 8);   --      IR @@@@ 8 RSHIFT 3 AND wm !            \ 1-00 W=B
                        aluop<="100";           --      4 aluop !                            \ 1-01 W=B/-2
                        wen<='1'; iasel<=ia_uo; --      1 wen !  ia_uo iasel !               \ 1-10 W=(W+CF)*2+YBN
                        cen<='1';               --      1 cen !   ( clear carry )
                    else                        --   ELSE
                        rdena <= '1';           --      1 rdena !                    
                        if IR(10)='1' then      --      IR @@@@ 400 AND IF
                            cen<='1';                   --  1 cen !
                            if IR(9)='1' then           --  IR @@@@ 200 AND IF                 \ 0110 Multiply step
                                wm<="11"; wen<='1';     --      3 wm !  1 wen !              \ 0111 CRC step
                                mul<='1'; cm<="01";     --      1 mul ! 1 cm !
                                wrenb<='1'; ubm<="1000"; --     1 wrenb ! 08 ubm !
                                if IR(8)='1' then       --      IR @@@@ 100 AND IF
                                    aluop<="111";       --          7 aluop !                   \ XOR instead of +
                                    wm<="00";           --          0 wm !
                                end if;                 --      THEN
                            else                        --  ELSE
                                if IR(8)='1' then       --      IR @@@@ 100 AND IF                 \ 0101 Div step 2
                                    div<='1'; cm<="01"; --          1 div ! 1 cm !
                                    uam<='1';           --          1 uam !
                                else                    --      ELSE                             \ 0100 Div step 1
                                    wrenb<='1';         --          1 wrenb !
                                    ubm<="1010";        --          0A ubm !
                                    cm<="01";           --          1 cm !
                                    wen<='1'; wm<="10"; --          1 wen ! 2 wm !
                                end if;                 --      THEN
                            end if;                     --  THEN
                        else                    --      ELSE
                            if IR(9)='1' then   --      IR @@@@ 200 AND IF                     \ A = (A | swapA) & B
                                uas <= IR(8);           --  IR @@@@ 100 bit? uas !
                                aluop<="101";           --  5 aluop !
                                wen<='1'; uam<='1';     --  1 wen ! 1 uam !
                                iasel<=ia_uo;           --  ia_uo iasel !
                                wrena<='1';             --  1 wrena !
                            else                        -- ELSE
                                if IR(8 downto 6) = "100" then -- IR @@@@ 1C0 AND 100 = IF    \ 7100: load REP count
                                    repen <= '1';       --   1 repen !
                                end if;         --           THEN
                                if IR(8 downto 6) = "101" then -- IR @@@@ 1C0 AND 101 = IF    \ 7140: load BANK
                                    banken <= '1';      --   1 banken !
                                end if;         --           THEN
                                -- \ room for other instructions here.
                            end if;             --         THEN
                        end if;                 --      THEN
                    end if;                     --   THEN ;

            end case;                           -- CREATE opcodz ~ op0 ~ op1 ~ op2 ~ op3 ~ op4 ~ op5 ~ op6 ~ op7
        end if;                                 -- ' opcodz IS opcodes
    end process decode;

-- \ -------------------------------------------------------------------------------------------------------------

-- ( synchonous processes )
    sync: process(clk) begin                    -- : process ( -- ) CPUdecode
    if rising_edge(clk) then
        resetd <= reset;                        -- reset resetd !!
        if  resetd='1' then                     -- resetd @@@@ IF
            cf <= '0'; ov <= '0';               --   0 cf !! 0 ov !!
            P  <= (others => '0');              --   0 P  !!
            W  <= (others => '0');              --   0 W  !!
            SP <= (others => '0');              --   0 SP !!
            RP <= (others => '0');              --   0 RP !!
            IR <= (others => '0');              --   0 IR !!
            bank    <= (others=>'0');           --   0 bank !!
            IRQpend <= (others=>'0');           --   0 IRQpend !!               \ clear interupt logic
            intd    <= (others=>'1');           --   -1 intd !!
            sleep   <= '0';                     --   0 sleep !!
            reps    <= (others=>'0');           --   0 reps  !!
        else                                    -- ELSE
            if    ipl/="000" then sleep <= '0'; --   ipl IF 0 sleep !!
            elsif drowsy='1' then sleep <= '1'; --   ELSE drowsy @@ IF 1 sleep !!
            end if;                             --   THEN THEN
-- ( clock the interrupt logic )
            intd <= int;                        --   int intd !!
            IRQpend <= IRQpend or               --   intd @@@@ INVERT  int AND
                (int and (not intd));           --   IRQpend @@@@ OR IRQpend !!
            if iack='1' then                    --   iack @@ IF
                case ipl is                     -- \ decode irq and clear request
                    when "001" => IRQpend(1) <= '0'; --  1 ipl LSHIFT INVERT
                    when "010" => IRQpend(2) <= '0'; --  IRQpend @@@@ AND
                    when "011" => IRQpend(3) <= '0'; --  IRQpend !!
                    when "100" => IRQpend(4) <= '0';
                    when "101" => IRQpend(5) <= '0';
                    when "110" => IRQpend(6) <= '0';
                    when others => IRQpend(7) <= '0';
                end case;
            end if;                             --   THEN
            if (hold='0') and (sleep='0') then  --   hold 0= sleep @@@@ 0= AND IF
                if flush='1' then               --     flush @@
                     IR <= flushIR;             --     IF   flushIR @@ IR !!     \ insert a NOP or special instr.
                elsif repeating='0' then        --     ELSE repeating 0=
                     IR <= PI;                  --        IF PI IR !! THEN              \ fetch next instruction
                end if;                         --     THEN
                if wen='1' then                 --     wen @@
                    W <= win;                   --     IF win W !! THEN
                end if;                         --
                if banken='1' then              --     banken @@
                    bank <= IR(5 downto 0);     --     IF IR @@@@ 03F AND bank !! THEN
                end if;                         --
                if (xen='1' or yax='1') then    --     xen yax @@ OR
                    if ssel='1' then RP <= spin; --    IF spin
                    else             SP <= spin; --       ssel @@ IF RP ELSE SP THEN !!     \ update selected ptr
                    end if;                     --     THEN
                end if;
                if repeating='1' then           --     repeating
                    reps <= reps - 1;           --     IF  reps @@@@ 1- reps !!
                else P <= pin;                  --     ELSE pin P !!                                    \ next P
                    if repen='1' then           --        repen @@                            \ load REP counter?
                        if IR(5)='1' then       --        IF  IR @@@@ 20 bit?
                             reps <= W(5 downto 1);  --       IF    W @@@@ 2/
                        else reps <= IR(4 downto 0); --       ELSE  IR @@@@
                        end if;                 --            THEN  1F and reps !!
                    end if;                     --        THEN
                end if;                         --     THEN
                if cen='1' then                 --     cen @@
                    cf <= cin;                  --     IF cin cf !!                   \ latch carry and overflow
                                                --        uoa &sign+1 0<> uoa &carry 0= AND yan@@ 0= AND ybn@@ AND
                                                --        uoa &sign+1 0= uoa &carry 0<> AND ybn@@ 0= AND yan@@ AND
                    ov <= (uoa(n+1) and not uoa(n+3) and not ya(n) and yb(n))
                       or (uoa(n+3) and not uoa(n+1) and not yb(n) and ya(n));
                                                --        OR 1 AND ov !!
                end if;                         --     THEN
            end if;                             --   THEN
        end if;                                 -- THEN
    end if;
    end process sync;                           -- ;

    t_P  <= P;                                  -- \ debugging instrumentation
    t_IR <= IR;
    t_W  <= W(n+1 downto 1);
    t_RP <= RP;
    t_SP <= SP;
    t_cv <= CF & ov;

end behavioral;

-- \ revision history:
-- \ 0: pre-release
-- \ 1: Inverted CF in condition codes 2 & 3 to correct unsigned comparisons.
-- \ 2: Changed Forth version of IPL to run faster.
-- \ 3: Added BANK for extended program memory fetch.








@ 1.1.1.1 log @Imported sources @ text @@