フォト
無料ブログはココログ

MyList

MCS51 SBC

MCS51 SBC


  1. はじめに

     捨てられない本がたくさんある。
    エレクトロニクスライフ1990/8「必ず身に付くワンチップマイコン技術」もその一つだ。ElectoronicsLife1990-8

     その頃には既に就職していて、PC-286Lという、286といいながら80286を使っていない、NECが作ったV30というIntelの8086互換CPUを使った、EPSONが作ったNECのPC-9801の互換機を使っていた。(ああややこしい)

    閑話休題

     この雑誌は、高周波からオーディオ、デジタル回路まで幅広く扱う良い雑誌だった。
    この月の特集は「必ず身に付くワンチップマイコン技術」といいながら、8052AH-BASICを使ったシングル・ボード・コンピュータの特集である。

     この雑誌を、懐かしく読んでいたら、8052AH-BASICはまだ手に入るのだろうかとふと思い、google先生に聞いてみたら簡単には見つからなかった。

     8052AH-BASICは、Intelのi8052の内臓ROMにBASIC-52を焼いたもので、BASIC-52のソースは公開されていて入手可能であることが分かった。

     であれば、ROMなしの8032の外部ROMにBASIC-52を焼くかEPROM版の8752にBASIC-52を焼こうと思い8032,8752を探したけれど見つからない。 8031,8051は富士通とか三菱とかNECとか見つかるのだが8032,8052,8752は見つからないのである。セカンドソースのライセンスをしなかったのかもしれない。

     ということで、とりあえず若松で見つけた、D8031(uPD8031ぢゃなよ),P80C31,MB8051を買って8031のSBCを作ってみた。
    8031<

     

  2. 構成

     エレクトロニクスライフの記事を見るとRAMは6264(8Kbyte)のSRAMを使っている。当時6116(2Kbyte)は安くなっていて、6246がお手頃価格になっていたのかな。今時は62256(32K)が\500以下だ。
    ここは、贅沢に32KをRAMにしてモニタをROMに書くことにしよう。モニタはどんなに大きくても2Kだ

     32KSRAM空間は当時とっても贅沢だった。尤も当時プログラムはアセンブラで書いていたので32Kメモリがあっても使えなかった。 しかし今は高級言語で書けるのでRAMは大きい方が良い。

     EZ-USBで遊んでいたときにはSDCCでF/Wを書いていのだが、EZ-USBの2Kのプログラム空間はかなり狭くてフルサイズのprintf()が使えないのでprintf_tiny()に手を入れて使っていた経験があるのでRAMは大きい方が良い。

     今回の用途は特定用途ではないのでROM化はしないで、プログラムはRAM上で動かして、I/Oは後から拡張できる構成にしよう。
    8031 + RAM(62256) + ROM(MON) の構成だと簡単に作れそうだ.。

    回路図はこんな感じ
    8031sbc_sch

    サンハヤトのICB-293Uに載りそうである。

     

  3. 実装
    ということで作ってみた。
    実装はこんな感じ
    8031sbc_layout

    8031sbc

     

  4. モニタ
     プログラムはCで書いて,RAMにロードしで動かすことにしよう。 昔は、高級言語といえばBASICくらいしかなかったので、Cで書けるのは夢のようだ。

     EZ-USBで遊んだ時にもSDCCを使っていたのだが、EZ-USBはUSB経由でプログラムをダウンロードできる仕掛けがあるのでプログラムのロードは非常に楽である。しかし、8031SBCでは、プログラムをRAMにロードできる機能を持ったモニタをROMに焼いておかなければならない。
     モニタに必要な機能は

    • プログラムロード
    • メモリダンプ
    • メモリ書き込み

     とりあえずこれくらいあれば使えるだろう.。

     モニタを自前で書く場合、8051のアセンブラは書いたことがないのでCで書くとになるけど、問題はどうやってモニタをデバッグするかである。

     EPROMはROMライタを買ったので焼けるけどROMイレーサがない。EPROMを使った試行錯誤はとっても大変なので、ここは巨人の肩に乗ることにしよう。

     ネットで探して見つけた8031のモニタではPaulmon2 が良さそうである。
    8031sbc_layout

    8031sbc_layout

     

  5. プログラム

     さすがにアセンブラでゴリゴリ書くのは大変なので、SDCCを使う。以前EZ-USBで遊んでいたときに使ったことがあるし。

    • まずは Hello World
      /*
      * hello world
      * Sep.2011 / Yoshi
      */
      #include <stdio.h>
      #include <mcs51>

      #include "io.h"
      #define printf printf_fast
      void main(void) {
              printf("Hello world!\n");
              exit(0);
      }

      io.c

      #include <stdio.h>
      #include <mcs51/8051.h>
      #include "paulmon2.h"
      #include "io.h"

      char getchar(void) {
              return pm2_cin();
      }

      void putchar(char c) {
              if (c=='\n') pm2_cout('\r');
              pm2_cout(c);
      }

      void exit(char c) __naked {
              c;
              __asm
              ljmp 0x0000
              __endasm;
      }

       pm2_cin(),pm2_cout()はPaulmon2への入出力サブルーチンへのインタフェースが記述されていてpaulmon2.cで定義されている。
       paulmon2.c, paulmon2.h は親切な人が公開しているのでぐぐると見つかる

    • コンパイル

      #sdcc -mmcs51 --model-small --code-loc 0x8000 hello.c io.rel paulmon2.rel

       

    • 実行結果

      Helloworld

       

    • 九九の表

      9x9

       printf_fast() は %3d のように出力幅を指定できるが %02x のように0で埋めることができない. printf_small() はその逆らしい。「帯に短したすきに長し」だ。

       EZ-USBで遊んでいたころにsdccを使っていた.  EZ-USBはCODE領域が2kしかないので,printf_tiny()しか使えずソースコードに手を入れて %02x がちゃんと出力されるようにして使っていた.
      8031SBCはcode領域が32kとれるのでとっても楽である。

    • 8Queen問題

       8Queen問題のプログラムを書いてみた。8Queen問題といえば再帰プログラムということで再帰で書いたのだが8051/31は内臓RAMが少ないので関数のネストが深くなる再帰プログラムは厳しい。
      DATAとSTACKをXRAMに移してもスタックが足りないようだ。よく見てみると、使った覚えのないiDataやBitsが使われている.(20h-2Dh)

       調べたところ、ライブラリで使われているようで、printf_small()をprintf()に変えると95byte使えるようになった。
      フルサイズのprintf()を使っているので、できたバイナリはかなり大きいが、CODEにSTACKは代えられない。

      --- 8queen.mem --
      Internal RAM layout:
            0 1 2 3 4 5 6 7 8 9 A B C D E F
      0x00:|0|0|0|0|0|0|0|0|a|b|c|c|c|c|c|c|
      0x10:|c|c|d|e|e| | | | | | | | | | | |
      0x20:|B|T|I|I|I|I|I|I|I|I|I|I|I|I|S|S|
      0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x80:| | | | | | | | | | | | | | | | |
      0x90:| | | | | | | | | | | | | | | | |
      0xa0:| | | | | | | | | | | | | | | | |
      0xb0:| | | | | | | | | | | | | | | | |
      0xc0:| | | | | | | | | | | | | | | | |
      0xd0:| | | | | | | | | | | | | | | | |
      0xe0:| | | | | | | | | | | | | | | | |
      0xf0:| | | | | | | | | | | | | | | | |
      0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute

       

      ようやく通った。

       

      -- 8queen.c ---
      Internal RAM layout:
            0 1 2 3 4 5 6 7 8 9 A B C D E F
      0x00:|0|0|0|0|0|0|0|0|a|b|b|c|d|e|e| |
      0x10:| | | | | | | | | | | | | | | | |
      0x20:|T|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
      0x80:| | | | | | | | | | | | | | | | |
      0x90:| | | | | | | | | | | | | | | | |
      0xa0:| | | | | | | | | | | | | | | | |
      0xb0:| | | | | | | | | | | | | | | | |
      0xc0:| | | | | | | | | | | | | | | | |
      0xd0:| | | | | | | | | | | | | | | | |
      0xe0:| | | | | | | | | | | | | | | | |
      0xf0:| | | | | | | | | | | | | | | | |
      0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute

       

    • 再帰関数

      再帰呼び出しする関数は次のとおりである。

      char place(char x, char y) __reentrant {
          static char n = 1;

          if (check(x,y)) {
              table[y] = x;
              if (y==7) {
                  printtb(n++);
                  return FALSE;
              } else {
                  if (place(0, y+1)) {
                      return TRUE;
                  } else {
                      table[y] = 0xff;
                      if (x==7)
                              return FALSE;
                      else    return place(x+1,y);
                      }
                  }
          } else {
              if (x==7)
                      return FALSE;
              else    return place(x+1, y);
          }
      }

      ほんとうはこう↓したいのだが、 再帰レベルが増えるのでスタックが足りなくなる。

      char place(char x, char y) __reentrant {
          static char n = 1;

          if (7<=y) {  /* 解 */
              printtb(n++);
              return FALSE;
          }
          if (7<=x) {  /* 見つからない */
              return FALSE;
          }

          if (check(x,y)) {
              table[y] = x;
              place(0, y+1);
              table[y] = (u_char)-1;
          }
          return place(x+1, y);
      }

     

  6. P8052AH-BASIC

     P8052AH-BASIC をとうとう見つけた.

     マルツの特価半導体を眺めていたら特価現品限りで8052AHが出ていた。web上の画像はマーキングが消してあったので、P8052AH-BASICかどうかは判らなかったけど、まあ1つ買ってみるかと注文したらP8052AH-BASICだった。

    8052basic

    じゃあ、8052AH-BASIC SBCを作ってみるかと...
    -- 2012/4/16 --

    作った
    -- 2012/11/12 --

     


[Yoshiのブログ]

 

 

 

コメント

コメントを書く

コメントは記事投稿者が公開するまで表示されません。

(ウェブ上には掲載しません)