散歩師・漫画居士のくだらなクラブ日記

ども、散歩師・漫画居士っす。散歩したり実働模型作ったりが趣味なんで、その時に思いついたこととか書くッス

OP16 CPU

もう'17年から、ボーッとopコード4bit固定、16種類のCPUを考えてるですが、

UMA向けの模型、AN式誘導機を優先するため、またもペンディングします。

特に割り込み周りが出来てなです。

いつ再開するかは未定。

 

現在の仕様はこんなカンジ。

--

================
= OP16 マイコン 仕様書
================                                                    NAFuMA

= レジスタ
================
PC/16   Program Counter
    基本的にアドレスが大きい方に1づつ進む
    本機はハーバードアーキテクチャーなので、
    プログラムカウンタが指すのは、プログラムメモリ
    *(書き込みでは特殊な振る舞いをするので、後序する
ACM/16  Accumulator
    データの一時保管レジスタ
    Immidiate値、DataMemoryAddress,ALUIn0,ALUOut0などは
    このレジスタを経由する。
    アドレスを割り付けるかもしれいないが、
    意味のある動作はできないだろう。
DP/16   DataPointer
    データスタックのポインタ。
RP/16   ReturnPointer
    SubRoutineの帰還アドレスや、Nesting変数などを
    格納するReturnStackのポインタ。
    本機では、DataとReturn値のポンタを分ける。
IRQ/15  IRQ vector
    割り込みのベクターを保持するレジスタ
    MSB[15]bitは、IRQ[14:0]のORであり、
    irc OPCodeでは、MSBをチェックしている。
    USRがRTLを作り込んで実現する。
RD/16   ReadData
    read値を一時保管するレジスタ
    アドレスは割り付けるかもしれないが、
    有意味のデータは得られないだろう
OPC/4   OP Code
    OP Codeがラッチされている。
    この値がマイクロプログラムのコードとして解釈される。
    解釈なしに、コードがそのまま入る。
OPR/4   OPeRand
    OPerandがラッチされ、ALUに、モードとして供給される。
    どのタイミングで更新されるかはTBD中。
RED/1   Read Do
    DataMemory Readのセマフォ。どの様に推移させるかはTBD中。
WTD/1   Write Do
    DataMemory Writeのセマフォ。どの様に推移させるかはTBD中。

PRA/16  PGMEM Adress
PRD/16  PGMEM Data

(adressは未決定)

GPIO/???16bit x (256-16)word.
    peripheralの専有アドレスは、TBD
    というか、userがRTLでコードして決めることになるが、
    専有が小さい場合、システム寄りの場合、$0010~$01FFを推奨。
    逆にVRAMやDMAを要するようなbufferの場合、$C000以上の高位が良いだろう。
    インタープリターを実装する場合は、その中間か


- ステータスレジスタ
    本機にステータスレジスタはありません。
    これは割り込み処理の単純化に配慮したものです。
    ステータスレジスタが必要な場合、スタックを消費して実現してください。

= OPecode
================
コード予約語は小文字とする。ユーザ定義は大文字(RTLコードではない。)

 OPCode  別名        意味                    動作
------------------------------------------------------------------------------
. dup   dup  push   push                (A|B C D -- A B|B D)
. drp   drop pop    pop                 (A B|C D -- A|B B D)
. dpi   > DPinc     DataPointer inc1    (A B|C D -- A B D|C) 
. dpd   < DPdec nip DataPointer dec1    (A B|C D -- A |C B D)
. nan   nand        nand                (A B|C D -- A|~(B&C) B D)
. add   +           add                 (A B|C D -- A|(B+C) B D)
. bol   bool        booling             (A B|C D -- A B | ( (C != 0)? -1 :0) B D)
. lda               load Address        (A B|Adr D -- A B|@Adr)
. sta               store Address       (A B Dat|Adr D -- A |B Dat D) @Adr<=Dat
. cal   call        call                (A B|Adr -- A|B)(R: -- PC+1)PC<=Adr
. ret               return              (R:Rt --) PC<=Rt
. irq               Interupt Check      *** TBD ***
. li1   LDI1        load imidiate 1word (A B|C D -- A B C |{12'd0,D0} D)
. li4   LDI4        load imidiate 4word (A B|C D -- A B C |{D0,D1,D2,D3} D)
. al1   ALU21       ALU result store 1  (A B|C D -- A|ALU0 B D)
. al2   ALU22       ALU result store 2  (A B|C D -- A ALU0|ALU1 C D)
------------------------------------------------------------------------------
* OPCodeの値はTBD irqが0だけ決まってる。
* 動作説明の説明

(P3 P2 P1 |ACM P0 -- P3 P2 |P1 P1 P0) 
    (処理前のDataスタック,ACM -- 処理後のDataスタック,ACM)
    |ACM            |の右がACMの値
    P0=@DP          P0はDP(データポインタの示す値)
    P1=@(DP-1)      P1はDP-1の示す値
                        DPは積む(push)で1増える。
    P2=@(DP-2)
    P3=@(DP-3)
    - DPの指すアドレスは、基本的に|ACMの一つ右。(例外もある。)

(R:Adr -- )
    (R:処理前リターンポインタの
    
================
= al1 (ALU21)
================
// and      or      nor     xor     xnor
// inhb     sub 
// bitc     bset    bclr    
// eq       ge      gr
// jadr
       oprand  意味    動作
AND_  : an     and     {YYs0} = DATs1_i & DATs0_i ;
OR_   : orr    or      {YYs0} = DATs1_i | DATs0_i ;
NOR_  : norr   nor     {YYs0} = ~(DATs1_i | DATs0_i) ;
XOR_  : eor    xor     {YYs0} = DATs1_i ^ DATs0_i ;
XNOR_ : enor   xnor    {YYs0} = ~(DATs1_i ^ DATs0_i) ;
INHB_ : inhb   inhbit(禁止)     //(AB --A&(~boolB))
                        {YYs0} = (DATs0_i!=0) 0 : DATs1_i ;
SUB_  : sub     引き算  {YYs0} = DATs1_i - DATs0_i;
BITC_ : btc     bit chek 
                        {YYs0} = 1&(DATs1_i>>DATs0_i[3:0]);
BSET_ : bst     bit set         // DATs1_iの[DATs0_i]のbitを1にsetする。
                        {YYs0} = DATs1_i | (1<<DATs0_i[3:0]);
BCLR_ : bcr     bit clear       //DATs1_iの[BITs0_i]bit を 0にclearする
                        {YYs0} = DATs1_i&(~(1<<DATs0_i[3:0]));
EQ_   : eq      一致            //(DATs0_i==DATs1_i)なら-1。でなければ0を返す
                        {YYs0} = (DATs1_i==DATs0_i)?-1:0;
GR_   : gr      大きい          //(DATs1_i>DATs0_i)なら-1。でなければ0を返す
                        {YYs0} = (DATs1_i>DATs0_i)?-1:0;
GE_   : ge      大きいかか同じ  //(DATs1_i>=DATs0_i)なら-1。でなければ0を返す
                        {YYs0} = (DATs1_i>=DATs0_i)?-1:0;
JADR_ : jad     jdgがFalseなら-1、でなければADRを返す。JPフィルタの補助
                            //(jdg ADR -- ADR/-1)
                        {YYs0} = (DATs1_i!=0)?DATs0_i : -1;

and,orなどは、verlogの予約語なので、oprandには避けている

================
= al2 (ALU22)
================
// ALU22
// sw       neg     neg32
// sub      abs     abs32   sadd    ssub    add12
// swp      mul     sft     ssft    maxmin  smaxmin
// MSB      lsb
// 

// notはdup nan で実現。2wordなので、ALU22を使うメリットがない。

sw SWP_:                   {YYs1,YYs0}=
                                {DATs0_i,DATs1_i};//SW_=5'h10

NEG_:`b               {YYs0} = -(DATs0_i);
                        YYs1=DATs1_i;
`e
NEGS32_:               {YYs1,YYs0} = -{16'h0,DATs0_i} ;
ABS_:`b                 YYs0=(DATs0_i[15])?(-DATs0_i):DATs0 ;
                        YYs1=DATs1_i;
`e
ABS32_:                 {YYs1,YYs0} = 
                            (DATs1_i[15])
                            ?   (-{DATs1_i,DATs0_i}) 
                            :     {DATs1_i,DATs0_i} 
                        ;
SADD_:                  {YYs1,YYs0}=
                              {{16{DATs1_i[15]}},DATs1_i}
                            + {{16{DATs0_i[15]}},DATs0_i} 
                        ;
SSUB_:                  {YYs1,YYs0}=
                              {{16{DATs1_i[15]}},DATs1_i}
                            - {{16{DATs0_i[15]}},DATs0_i} 
                        ;
ADD12_:                 {YYs1,YYs0}=
                             {16'h0,DATs1_i}
                            +{16'h0,DATs0_i} 
                        ;
SUB12_:
                        {YYs1,YYs0}=
                             {16'h0,DATs1_i}
                            -{16'h0,DATs0_i} 
                        ;
MSB_:`b                 YYs0= 1 & (DATs0_i>>15) ;
                        YYs1= DATs1_i;
`e
MUL_:                   {YYs1,YYs0}=
                            {16'h0,DATs0_i} * {16h0,DATs1_i};
SFT_:                   {YYs1,YYs0}=
                            {16'h0,DATs1_i}<<DATs0_i;
SSFT_:                  {YYs1,YYs0}=
                            {{16{DATs1_i[15]}},DATs1_i}<<DATs0_i;
MAXMIN_:                {YYs1,YYs0}=
                            (DATs1_i>=DATs0_i)
                            ?   {DATs1_i,DATs0_i}
                            :   {DATs0_i,DATs1_i}
                        }
SMAXMIN_:                {YYs1,YYs0}=
                            ({~DATs1_i[15],DATs1_i[14:0]}
                                >`{DATs0_i[15],DATs0_i[14:0]})
                            ?   {DATs1_i,DATs0_i}
                            :   {DATs0_i,DATs1_i}
                        ;
MUL_:                   {YYs1,YYs0}=
                            {16'h0,DATs1_i}*{16'h0,DATs0}
                        ;

 

================
= shortened(短縮)subroutine
================
- Shortened(短縮)subroutine は
    li1 <entry> cal の3wordで呼び出せる 16種類のサブルーチン郡。
    - まだ絞りきれてない
    - ソフトウエアのみで変更可能。
//  LDS(pick)STS     SEL     N_GET
//  ROT     RROT    TUCK    RROL
//  OVER    TUKN    ROLL
//  DFOR    DNEXT   RJP     RCAL

//  FLT     ZIP     MAP     REDUCE  LEN
//  JRCL 
//  N_GET   i_GET   n_GET   m_get   j_get


// LDS  (A Ofs -- A Var)//7
{dup,nan,li,DP_,add,lda,ret}
// STS  (A DAT ops -- A)//7
{dup,nan,li,DP_,add,sta.ret} //15
// SEL  (A F Jdg T -- A sel)
{sw,dup        //(A F T J J
,<,sw,>          //(A F J T J
,nan            //(A F J T'
,sw,nip,sw,bst      //(A T' F J
,dup,nan
,nan
,nan,ret}
 
//RJP   (A Ofs -- A)(R:Rt -- Ofs+PC) 
{li,RP_,li,1_,add,lda    //(A ofs Rt
    ,add,li,RP_,li,1_,add,lda,sta,ret}

 

================
= PCの動作
================
- 本機のPCの動作は
- 特殊条件ジャンプ
    PCには16'hFFFFは書き込めず、
    PCはPC+1にincrementされる。
    これによって、jadと組み合わせることで、条件ジャンプを可能にしている。
    <例>  num が <cmp number>なら <ADR>にジャンプ (num -- )
        li4 <cmp number> al1 eq li4 <adr> al1 jad li1 <PC> sta

- 短縮サブルーチン用アドレス変換
    adr $0000-$000Fは、それそれ$0080,$0088,$0090,$0098..$00F8に直接転送される。
    これによって、adr$0000-$000Fはそれぞれ8wordのjump命令などを実装でき、
    短縮サブルーチンエントリーとして使える。
    - 通常のサブルーチンcall
        li4 A3 A2 A1 A0 cal                 //6word必要だが
    - 短縮エントリーcall
        li1 <short subRoutine Entry> cal    //3wordで済む。
    Z80の RST命令に近い。

- マッパー(未実装
    $4000アドレス単位にマッパを持ち、
    RTL実装で、自動ページ切り替えができればと考えてる。
    mappa1->mappa2->mappa14->mappa13の様に任意にマッパが切り替わるが、
    PCから見た見かけのアドレスは、$4000内にとどまる。様なやつ
    - システムの0ページのみは固定。
    - マッパサイズは$4000,$2000にするべきか迷い中。(0ページを実装で変えたいため)
================
= irc
================
- 本機では、1OPCでスタックを扱い切れない。
    スタック処理の途中で割り込みが入ると、
    割り込んだ側がスタックを破壊してしまう。
    このため、毎OPCごとに割り込みを受け付ける処理は行えない
    何か割り込み処理を行うために、ircコードをリザーブしている。
- 今はTBDだが、ircコマンドで、アプリ側がポーリングすることにするか?
    (プリエンプティブは諦める型

================
= Dataメモリアクセス
================
================
= Prgメモリアクセス
================
- 構成
    - その1
        データRAMの上位にPRG メモリを配置する。
            PGMEM_RE (ADR -- dat)
                li 15 al1 bst lda
            PGMEM_WT (dat Adr --)
                li 15 al1 bst sta
        - 問題
            - 32k Wordしかアクセスできない
                - アクセスにマッパを考える?
                - 逆にDataMemが32kWは多分問題ない。
            - マッパが大変になる
    - その2
        PRG mem アクセスレジスタを介してアクセス。
            PGRMEM_RE   (ADR -- dat)
                li1 PGA sta li1 PGD lda
            PGMEM_WT    (DAT ADR --)
                li1 PGA sta li1 PGD sta
        - 問題
            - FFを32bit消費する。
            - HW 的にwaitをどうとるか考える必要がある。
            - ちょっと遅い(そうでもないか?
                - むしろ クロック単位のdlyを吸収しやすいか?
            - 貴重な最初16アドレスを2コマも使う
        
        
- プログラムの転送
- ランダムアクセス

================
= メモリー
================
- DataもProgも16bit wordとする。

= Prog MEM
前詰めに配置する。
- Prgとしてのアクセス
  - PC(Program Counter)による read    opc フェッチ
    PCからのアクセスは、上位14bitで16bitアドレスを選択する。
    下2bitで4bit word select
  - PC write
    PCによるアクセスwriteはない。
    書き込むのには、Dataとしてアクセスする。(staコマンド)
- Data としてのアクセス
    - Read
        16bit アドレスでアクセス
    - write
        16bit アドレスでのアクセス
= Data Mem
0ページ目はレジスタアサインしているので、そこだけは避ける。
プログラムと供給するときは???
- Read
   一般的なアクセス
- Write
    一般的なアクセス
- opcフェッチ
    Data Memのスタートアドレス設定によっては、
    PCでアクセスできない。イメージにするべきかは???

--