ブログの練習

ブログを書く練習です。
最近はレトロな計算機(電卓、マイコン、パソコンなど)
に関することを書き始めました。

Intel 4004 (その8) シリアル通信を実装する

2023-02-03 11:51:02 | マイコン(4004)
4004でシリアル通信するためのプログラムを書いてみました。いわゆるソフトウェアUARTというやつです。GitHubに下記の前例があったので参考にしましたが、基本的にプログラム自体はゼロから書きました。

GitHub - jim11662418/4004-SBC: Home-brew Intel 4004 Single Board Computer

Home-brew Intel 4004 Single Board Computer. Contribute to jim11662418/4004-SBC development by creating an account on GitHub.

GitHub

 

参考にしたのは、開発環境(The Macroassembler AS)、PRINTルーチンと文字列データは256byte単位の同一ページ内に置く、putcharではstart bitとstop bit をキャリーに入れておくとシンプルになるというあたりです。前例では4800bpsがmaxのようでしたが、今回9600bpsまで実現することができ、NoritakeのVFD(CU22042)でそのまま表示させことができました。
まとまったらGitHubに載せる予定ですが、とりあえず今回書いたコードをここに載せます。
ハードウェアは入力が4004のTEST端子、出力は4002の出力ポート(作業用に4bit全部使っていて、LSBが実際の出力)です。前回の記事に書いたように、フォトカプラでレベル変換しています。

まずはGETCHARです。やってることはコメントに拙い英語で書いた通りですが、ポイントをまとめると下記の通り。
・4004の実行速度は10.8003857us/cycle(5.185MHzの水晶使用)
・9600bpsは9.645cycle/bit
・start bitをポーリングで検出すると0~2cycleの遅れになるんだけど、さらにちょっと(1~4サイクル)遅らせたあたりでbitの0/1判定すれば良さそう。
・bit0~bit3, bit4~bit7を9cycle間隔、bit3~bit4を12cycle、bit7~stop bitを10cycle ぐらいにしておけばbitの有効領域で判定できそう。

;;; functuon for setting counter for ISZ loop
loop            function x, (16-(x))
;;;---------------------------------------------------------------------------
;;; GETCHAR
;;; receive a character from serial port (TEST) and put into P1(R2, R3)
;;; baud rate: 9600bps (104.17us/bit, 9.645cycle/bit)
;;;
;;; Input: none
;;; Output: P1(R2,R3), ACC=0(OK), ACC=1(error)
;;; Working: P6, P7
;;; This subroutine destroys P6, P7.
;;;---------------------------------------------------------------------------
;;;
;;;          |--12--|-9--|-9-|-9--|-12--|-9--|-9-|-9--|-10--|
;;; ~~~~~~~~|____|~~~~|____|~~~~|____|~~~~|____|~~~~|____|~~~~~ 9.645cycle/bit
;;;          ^      ^    ^   ^    ^     ^    ^   ^    ^     ^
;;;        start    0    1   2    3     4    5   6    7    stop
;;;               |->phase delay
;;; - In order to check data bits in the middle of the signal,
;;;   a "phase delay" should be added between the start bit and data bits.
;;;   (1 to 4 cycles may be moderate for 9.645cycle/bit)
;;; - Detection of the start bit may cause delay of 2 cycles due to polling.
;;;---------------------------------------------------------------------------

GETCHAR:
        FIM R12R13, loop(4)     ; loop for first(lower) 4 bit
                                ;
        JCN TN, $               ;(2) wait for start bit (TEST="0")
        FIM P7, loop(4)         ;(2)
        ISZ R15,$               ;(8) 12 cycles between startbit and bit0
                                ;    phase(bit0)= 12 -9.645 = 2.355cycle
GETCHAR_L1:
        JCN TN, GETCHAR_L2      ;(2) check a bit
        CLC                     ;<1> TEST="0" then CY=0
        JUN GETCHAR_L3          ;<2>
GETCHAR_L2:
        STC                     ;[1] TEST="1" then CY=1
        NOP                     ;[1]
        NOP                     ;[1]
GETCHAR_L3:
        RAR                     ;(1) load CY->ACC
        NOP                     ;(1) 9cycle/bit (error=-0.645 cycle/bit)
        ISZ R13, GETCHAR_L1     ;(2) repeat until 4 bit received
                                ;    phase(here)= 2.355 -0.645*3 = 0.42cycle
        XCH R3                  ;(1)
        FIM R12R13, loop(4)     ;(2) loop for second(upper) 4 bit
                                ;    12 cycles between bit3 and bit4
                                ;    phase(bit4)= 2.42 +12 -9.645 = 2.775cycle
GETCHAR_L4:
        JCN TN, GETCHAR_L5      ;(2) check a bit
        CLC                     ;<1> TEST="0" then CY=0
        JUN GETCHAR_L6          ;<2>
GETCHAR_L5:
        STC                     ;[1] TEST="1" then CY=1
        NOP                     ;[1]
        NOP                     ;[1]
GETCHAR_L6:
        RAR                     ;(1) load CY->ACC
        NOP                     ;(1) 9cycle/bit (error=-0.645 cycle/bit)
        ISZ R13, GETCHAR_L4     ;(2) repeat until 4 bit received
                                ;    phase(here)= 4.755 -0.645*3 = 0.84 cycle
        XCH R2                  ;(1)
                                ;    10 cycles/between bit7 and stopbit
                                ;    phase(stop)= 2.84 +10 -9.645 = 1.195cycle
        ;; check stop bit
        JCN TN, GETCHAR_OK      ; stop bit == "1"
        BBL 1                   ; stop bit != "1"
GETCHAR_OK:
        BBL 0


次にPUTCHARです。基本的にGETCHARと同じ考え方です。
正確には9.645cycle/bitという半端なタイミングで出力する必要があるのですが、前半を9cycle/bit、後半を10cycle/bitで出力すれば許容範囲だよねという考え方です。

;;;---------------------------------------------------------------------------
;;; PUTCHAR
;;; send the character in P1(R2, R3) to OUTPORT
;;; baud rate: 9600bps (104.17us/bit, 9.645cycle/bit)
;;;
;;; Input: P1(R2,R3)
;;; Output: ACC=0
;;; Working: P6(R12R13), P7
;;; This subroutine destroys P6, P7.
;;;---------------------------------------------------------------------------
;;;
;;;         |--9-|-9--|-9-|-9--|-10--|-10-|-10-|-10-|-10--|(ave.9.56cycle/bit)
;;; ~~~~~~~~|____|~~~~|____|~~~~|____|~~~~|____|~~~~|____|~~~~~ 9.645cycle/bit
;;;         ^    ^    ^   ^    ^     ^    ^    ^    ^     ^
;;;       start  0    1   2    3     4    5    6    7     stop
;;;---------------------------------------------------------------------------

PUTCHAR:
        LDM BANK_SERIAL     ; bank of output port
        FIM P7, CHIP_SERIAL ; chip# of output port
        DCL                 ; set port bank
        SRC P7              ; set port address

        FIM R12R13, loop(5) ; start bit and lower 4bit(R3)
        LD R3
        CLC                 ; start bit is 0
        RAL

PUTCHAR_L1:
        NOP                 ;(1) 9cycle/bit
        NOP                 ;(1)
        NOP                 ;(1)
        NOP                 ;(1)
        NOP                 ;(1)
        WMP                 ;(1)
        RAR                 ;(1)
        ISZ R13, PUTCHAR_L1 ;(2)

        FIM R12R13, loop(5) ;(2) upper 4bit(R2) and stop bit
        LD R2               ;(1)
        STC                 ;(1) stop bit is 1
        NOP                 ;(1) timing adjustment
        NOP                 ;(1) 10cycle between bit3 and bit4
PUTCHAR_L2:
        WMP                 ;(1) 10cycle/bit
        FIM R14R15, loop(2) ;(2)
        ISZ R15, $          ;(4)
        RAR                 ;(1)
        ISZ R13, PUTCHAR_L2  ;(2)

        BBL 0

試したところちゃんと動いてくれました。ソフトウェアUARTでこれ以上速くするのは無理そうかな。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする