オープンソースのUART16550モジュールをAHB-Liteバスに移植してから1か月を過ぎました。 MIPSfpgaの中断に関する記事はまだ公開されていなかったため、その時点でそれについて書くことは多少論理的ではありませんでした。
経験豊富な開発者であれば、有益なニュースが1つだけあります。UART16550がMIPSfpga-plusシステムに追加されました。これ以上読むことはできません。 そして、このモジュールの逆アセンブルされた例に興味がある人のために-catへようこそ。
はじめに
読者は:
- ハリスとハリスの教科書の巻の主題領域に精通している[ L1 ];
- ソースコードMIPSfpga [ L2 ]およびmipsfpga-plus [ L3 ]にアクセスできます。
- 彼は、UARTの使用を含む(任意のアーキテクチャの)マイクロコントローラのプログラミングの経験があります。 UARTがどのようなものかをここで更新できます[ L4 ]。
UART16550とは何ですか?
このマイクロ回路の外観の歴史は[ L5 ]で詳しく説明されていますが、グーグル[ L6 ]でそのドキュメントを見つけることができます。
- それは非常に普及しています。
- Linuxカーネルでサポートされています。
- verilog [ L7 、 L8 、 L9 ]のオープンソース実装は長い間存在していましたが、Wishboneバス用です。
- この実装をMIPSfpgaで使用されるAHB-Liteバスに移植するコストは、約100行のコード[ S1 ]です。
module mfp_ahb_lite_uart16550( //ABB-Lite side input HCLK, input HRESETn, input [ 31 : 0 ] HADDR, input [ 2 : 0 ] HBURST, input HMASTLOCK, // ignored input [ 3 : 0 ] HPROT, // ignored input HSEL, input [ 2 : 0 ] HSIZE, input [ 1 : 0 ] HTRANS, input [ 31 : 0 ] HWDATA, input HWRITE, output reg [ 31 : 0 ] HRDATA, output HREADY, output HRESP, input SI_Endian, // ignored //UART side input UART_SRX, // UART serial input signal output UART_STX, // UART serial output signal output UART_RTS, // UART MODEM Request To Send input UART_CTS, // UART MODEM Clear To Send output UART_DTR, // UART MODEM Data Terminal Ready input UART_DSR, // UART MODEM Data Set Ready input UART_RI, // UART MODEM Ring Indicator input UART_DCD, // UART MODEM Data Carrier Detect //UART internal output UART_BAUD, // UART baudrate output output UART_INT // UART interrupt ); parameter S_INIT = 0, S_IDLE = 1, S_READ = 2, S_WRITE = 3; reg [ 1:0 ] State, Next; assign HRESP = 1'b0; assign HREADY = (State == S_IDLE); always @ (posedge HCLK) begin if (~HRESETn) State <= S_INIT; else State <= Next; end reg [ 2:0 ] ADDR_old; wire [ 2:0 ] ADDR = HADDR [ 4:2 ]; wire [ 7:0 ] ReadData; parameter HTRANS_IDLE = 2'b0; wire NeedAction = HTRANS != HTRANS_IDLE && HSEL; always @ (*) begin //State change decision case(State) default : Next = S_IDLE; S_IDLE : Next = ~NeedAction ? S_IDLE : ( HWRITE ? S_WRITE : S_READ ); endcase end always @ (posedge HCLK) begin case(State) S_INIT : ; S_IDLE : if(HSEL) ADDR_old <= ADDR; S_READ : HRDATA <= { 24'b0, ReadData}; S_WRITE : ; endcase end wire [ 7:0 ] WriteData = HWDATA [ 7:0 ]; wire [ 2:0 ] ActionAddr; wire WriteAction; wire ReadAction; reg [ 10:0 ] conf; assign { ReadAction, WriteAction, ActionAddr } = conf; always @ (*) begin //io case(State) default : conf = { 2'b00, 8'b0 }; S_READ : conf = { 2'b10, ADDR }; S_WRITE : conf = { 2'b01, ADDR_old }; endcase end // Registers uart_regs regs( .clk ( HCLK ), .wb_rst_i ( ~HRESETn ), .wb_addr_i ( ActionAddr ), .wb_dat_i ( WriteData ), .wb_dat_o ( ReadData ), .wb_we_i ( WriteAction ), .wb_re_i ( ReadAction ), .modem_inputs ( { UART_CTS, UART_DSR, UART_RI, UART_DCD } ), .stx_pad_o ( UART_STX ), .srx_pad_i ( UART_SRX ), .rts_pad_o ( UART_RTS ), .dtr_pad_o ( UART_DTR ), .int_o ( UART_INT ), .baud_o ( UART_BAUD ) ); endmodule
主要な実装機能
- プロジェクト[ L8 ]は基本ソリューションとして採用され、これは[ L7 、 L9 ]に基づいています。
- 基本的なソリューションと比較して、Wishboneバスに関連付けられたコードはプロジェクトから除外されています。 AHB-Liteの対応するインターフェイスモジュール(mfp_ahb_lite_uart16550)[ S1 ]に置き換えられました。
- 基本プロジェクトから借用したすべてのコードは、uart16550 [ S2 ]ディレクトリにあります。
- mfp_ahb_lite_uart16550モジュールは継続的にシステムに組み込まれ、mfp_ahb_lite_matrix_config.vhファイルのMFP_USE_DUPLEX_UART [ S3 ]オプションがUART_SRXおよびUART_STX信号の可用性を決定します。
- 既存のUART_RXおよびUART_TX信号の場合、次の使用手順が提供されます。
UART_RX-モードに関係なく、以前のようにファームウェアをシステムメモリにダウンロードするためにのみ使用されます(mfp_uart_receiverモジュールはUART16550には適用されません)。 MFP_USE_DUPLEX_UARTオプションがアクティブでない場合、UART_TXを使用してUART16550から外部にデータを転送します;この場合、受信は利用できません。 MFP_USE_DUPLEX_UARTオプションがアクティブな場合、UART_TXは使用されず、 UART_SRXおよびUART_STX [ S4 ]が/からmfp_ahb_lite_uart16550へのデータ転送に使用されます。 - モジュールの最上位レベルへのモデム制御インターフェースの出力は実行されませんでした。 対応する行はモジュールのahb_lite_uart16550インターフェースで利用可能であり、必要に応じて使用できます( UART_RTS、UART_CTS、UART_DTR、UART_DSR、UART_RI、UART_DCD )[ S5 ];
- 割り込み信号( UART_INT )は、下位互換性とベクトルモードのために、入力hw3(信号SI_Int [3] )に接続されています。 そして、外部割り込みコントローラーのeic5(信号EIC_input [5] )へ[ S6 ];
- シミュレーションモードで実行している場合、 UART_STX行は UART_SRXに閉じられます [ S7 ]。
- シミュレーションモードで得られたソリューションの効率は、Modelsimを使用して確認されました。
- ハードウェアでの操作性は、Terasic DE10-Liteボード[ L10 ]でテストされました。
- UART16550の使用例として、05_uart [ S8 ]と08_uart_irq [ S9 ]の2つのプログラムが作成されました。リセット後、uart(8n1、115200)がセットアップされ、挨拶が送信されます。その後、受信した各文字のコードがLEDと7セグメントインジケーターに表示されます。 ボードで開始すると、uartが受け取った各キャラクターは送り返されます。
- 開発されたモジュールのデバッグは、プロジェクトのフレームワーク内のmipsfpga +コードから「分離して」利用可能です[ L11 ]。
- モジュールのソフトウェア構成については、基本プロジェクトのドキュメント[ D1 ]を使用してください。 以下の例をよりよく理解するために、それをよく理解することをお勧めします。
- AHB-Liteバスの使用については、[ D2 ]で詳細に説明されています。
例
起動順序
次の設定[ S3 ]がmfp_ahb_lite_matrix_config.vhファイルに設定されていることを確認します。
`define MFP_USE_DUPLEX_UART
- プログラムがあるディレクトリに移動します。mipsfpga-plus / Programs / 05_uart [ S8 ]、または08_uart_irq [ S9 ];
main.cファイルセット[ S10 ]:
#define RUNTYPE SIMULATION
プログラムをビルドし、シミュレーターで実行します。
02_compile_and_link.bat 05_generate_verilog_readmemh_file.bat 06_simulate_with_modelsim.bat
- シミュレーションスクリプトの完了後、「いいえ」をクリックして、シミュレータが閉じないようにします。
- このコードが「ハードウェア上」で機能する方法は、ヘッダーgifで確認できます。
プログラムとシステム構成の説明
- 例08_uart_irqは、UART16550自体の構成に加えて、それが生成する割り込みも使用するため、この構成は以下で考慮されます。
- コントローラーレジスターでの作業を提供するディレクティブは、ヘッダーファイルuart16550.h [ S11 ]で提供されます。
起動時に、UART16550 [ S12 ]が構成されます。
void uartInit(uint16_t divisor) { // 8n1 uart mode MFP_UART_LCR = MFP_UART_LCR_8N1; // Divisor Latches access enable MFP_UART_LCR |= MFP_UART_LCR_LATCH; // Divisor LSB MFP_UART_DLL = divisor & 0xFF; // Divisor MSB MFP_UART_DLH = (divisor >> 8) & 0xff; // Divisor Latches access disable MFP_UART_LCR &= ~MFP_UART_LCR_LATCH; //enable Received Data available interrupt MFP_UART_IER = MFP_UART_IER_RDA; //set 4 byte Receiver FIFO Interrupt trigger level MFP_UART_FCR = MFP_UART_FCR_ITL4; }
-
void mipsInterruptInit(void) { // Status.BEV 0 - vector interrupt mode mips32_bicsr (SR_BEV); // Cause.IV, 1 - special int vector (0x200) // where 0x200 - base for others interrupts; mips32_biscr (CR_IV); // get IntCtl reg value uint32_t intCtl = mips32_getintctl(); // set interrupt table vector spacing (0x20 in our case) // see exceptions.S for details mips32_setintctl(intCtl | INTCTL_VS_32); // interrupt enable, HW3 unmasked mips32_bissr (SR_IE | SR_HINT3); }
割り込み処理には、着信FIFOのデータの存在が原因であるかどうかの確認が含まれます[ S14 ]:
// uart interrupt handler void __attribute__ ((interrupt, keep_interrupts_masked)) __mips_isr_hw3 () { // Receiver Data available interrupt handler if(MFP_UART_IIR & MFP_UART_IIR_RDA) uartReceive(); }
読み取り値(FIFOが空になるまで)と出力[ S15 ]が続きます。
void uartReceive(void) { // is there something in receiver fifo? while (MFP_UART_LSR & MFP_UART_LSR_DR) { // data receive uint8_t data = MFP_UART_RXR; receivedDataOutput(data); #if RUNTYPE == HARDWARE uartTransmit(data); #endif } }
- 作業がハードウェアで行われた場合、すべての受信データが送り返されます[ S16 ]:
void uartTransmit(uint8_t data) { // waiting for transmitter fifo empty while (!(MFP_UART_LSR & MFP_UART_LSR_TFE)); // data transmit MFP_UART_TXR = data; }
以下はプログラムの結果です。 モジュールをセットアップするとき、4文字を受信した後に割り込み動作モードを設定するため、送信は受信のために一時的に中断されます。 残りの文字は、別の同様の割り込みの後に受信されましたが、すでにキューに4文字が存在するのではなく、空のキューとタイムアウトが原因ではありません(コントローラーはこれ以上文字がないことに気付き、キューが空ではないことを通知しました);
05_uartプログラムの場合、受信は、送信が完了した後にすでに実行されています。この間、受信データは受信側のFIFOで待機しています。
謝辞
著者は、教科書のデビッド・ハリスとサラ・ハリスの「デジタル回路とコンピューター・アーキテクチャ」 の翻訳者チーム 、現代のプロセッサー・コアのアカデミック・ライセンスについてはイマジネーション・テクノロジーズ 、MIPSfpgaの普及に関する仕事については個人的にユーリー・パンチュル・ユーリ・パンチュルに感謝しています。
参照資料
[L1]- デジタル回路とコンピューターアーキテクチャ 。
[L2] -MIPSfpgaの使用を開始する方法 。
[L3] -githubのMIPSfpga-plusプロジェクト 。
[L4]- ウィキペディア:UART ;
[L5]- ウィキペディア:UART16550 ;
[L6] -Google:UART16550 ;
[L7]- プロジェクトfreecores / uart16550 ;
[L8]- プロジェクトolofk / uart16550 ;
[L9]- プロジェクトのオープンコア/ UART 16550コア 。
[L10] -FPGA Terasic DE10-Lite ;
[L11]- プロジェクトahb_lite_uart16550 ;
[L12] -MIPSfpgaおよび割り込み 。
ドキュメント
[D1] -UART IPコア仕様 。
[D2] -MIPS32 microAptiv UPプロセッサーコアAHB-Liteインターフェイス 。
画像と表
[P1]- デバッグボードでの作業例 ;
[P2] -UART割り込みの処理モードで動作します 。
[P3]- レジスタを定期的にポーリングすることにより動作します。
ソースコードリンク
[S1]- モジュールmfp_ahb_lite_uart16550 ;
[S2]- カタログmipsfpga-plus / uart16550 ;
[S3]- オプションMFP_USE_DUPLEX_UART ;
[S4]- シグナルUART_SRXおよびUART_STX ;
[S5]- モデム制御インターフェース 。
[S6]- 割り込み信号の接続 。
[S7]- シミュレーションモードでのUART信号 。
[S8]- '05_uart'の使用例 ;
[S9]- '08_uart_irq'の使用例 ;
[S10]- サンプルプログラムの動作モードを設定します 。
[S11]- ヘッダーファイルuart16550.h 。
[S12]- ソフトウェア設定UART16550 ;
[S13]- 割り込みの設定 。
[S14] -UART割り込み処理 。
[S15]- 受信したUARTデータの読み取り 。
[S16]- 受信したデータを送り返します 。