豊四季タイニーベーシック

前回から随分と間が空いてしまいましたが...

豊四季タイニーベーシックを移植しました。

アセンブリ言語の勉強を兼ねてCコンパイラを使用せずに手作業でアセンブリ言語で作成しました。


起動時の表示
イメージ 1

フロー制御を設定していない場合は、内部コードへの変換に時間がかかる場合に、文字を読み飛ばしてしまう場合がある。
イメージ 2

フロー制御を指定
イメージ 3

フロー制御を指定すると正常に受信できる。
9600bpsを超える設定でも問題ありません。
イメージ 4

実行結果
イメージ 5

処理は最適化の余地があるので追々最適化をします。
※コマンドの追加も考えています。



VGA出力

なかなか進みませんが、SBC6809用のVGAキャラクタ表示ボードを作っています。

ようやく、Cmod S6(Spartan-6:XC6SLX4-2CPG196)からVGAで80x48文字のキャラクタ表示ができるようになりました。
文字サイズ:8x8ドットフォントの下に2ドットの空白で8x10ドット
表示色:文字色8色、背景色8色(VRAM的にはそれぞれ16色に拡張する余裕あり)
カーソル表示:0.8Hzのブリンク表示
画像の真ん中右側の「1」がカーソル位置
FPGAボードで学ぶ組込みシステム開発入門[Xilinx編]のVGA文字表示回路をカスタマイズしています。
5V⇒3.3V変換のための74AC541Pを注文していますので、届いたらユニバーサル基板で拡張ボード化する予定です。

イメージ 2

イメージ 1


CFボード

CFボードでIdentifyDriveコマンドを実行するプログラムと結果です。

ASSIST09と組み合わせて使用します。
実行結果
SanDiskの512MB CompactFlashです。
CapabilitiesからLBA/DMAに対応していることがわかります。
イメージ 1




ソース
1バイト読み込む毎にDRQをチェックするのが正しいようですが、
CPUが遅いためかDRQのチェックを行うと、読み飛ばしが発生するようで、
DRQのチェックを行わずに読み込みを行っています。
-----------------------

CF_PORT EQU $FFB0
CF_DATA EQU (CF_PORT+0) ;DATA
CF_ERR EQU (CF_PORT+1) ;READ:Error Register
CF_FEATURE EQU (CF_PORT+1) ;WRITE:Features
CF_SECT_CNT EQU (CF_PORT+2) ;WRITE:Sector count
CF_LBA0 EQU (CF_PORT+3) ;
CF_LBA1 EQU (CF_PORT+4)
CF_LBA2 EQU (CF_PORT+5)
CF_LBA3 EQU (CF_PORT+6)
CF_STAT EQU (CF_PORT+7) ;READ:status
CF_CMD EQU (CF_PORT+7) ;WRITE:command
ST_ERR EQU $1
ST_DRQ EQU $8
ST_DF EQU $20
ST_RDY EQU $40
ST_BSY EQU $80
DATA_BUF EQU $1000
 ORG ROM2OF
CF_TEST ;LDMD #1
 LEAX MSG1,PCR
 SWI
 FCB PDATA1
 JSR CF_INIT
 LDA #$EC ;EC:Identify Drive
 JSR CF_RD_CMD
 ;General configuration bit-significant information:
 LEAX H_INFO,PCR
 SWI
 FCB PDATA1
 LDX #DATA_BUF
 SWI
 FCB OUT4HS
 JSR PRCRLF
 ;Serial Number
 LEAX H_SN,PCR
 SWI
 FCB PDATA1
 LDX #(DATA_BUF+(10*2))
 LDB #20
 JSR PUTS
 JSR PRCRLF
 ;Firmware revision
 LEAX H_FIRM,PCR
 SWI
 FCB PDATA1
 LDX #(DATA_BUF+(23*2))
 LDB #8
 JSR PUTS
 JSR PRCRLF
 ;Model Number
 LEAX H_MODEL,PCR
 SWI
 FCB PDATA1
 LDX #(DATA_BUF+(27*2))
 LDB #40
 JSR PUTS
 JSR PRCRLF
 ;Capabilities
 LEAX H_CAPA,PCR
 SWI
 FCB PDATA1
 LDX #(DATA_BUF+(49*2))
 SWI
 FCB OUT4HS
 JSR PRCRLF
 ;TOTAL SECTORS
 LEAX H_SECS,PCR
 SWI
 FCB PDATA1
 LDX #(DATA_BUF+(60*2))
 SWI
 FCB OUT4HS
 LDX #(DATA_BUF+(61*2))
 SWI
 FCB OUT4HS
 JSR PRCRLF
 RTS
H_INFO FCC /INFORMATION:/
 FCB EOT
H_SN FCC /SERIAL NUMBER:/
 FCB EOT
H_FIRM FCC /FIRMWARE VERSION:/
 FCB EOT
H_MODEL FCC /MODEL NUMBER:/
 FCB EOT
H_CAPA FCC /Capabilities:/
 FCB EOT
H_SECS FCC /LBA Total Sectors:/
 FCB EOT
PUTS LDA ,X+
 PSHS B,X
 SWI  ;SEND TO OUTPUT HANDLER
 FCB OUTCH ;FUNCTION
 PULS B,X
 DECB
 BNE PUTS
 RTS
;***************************************************************************
;CF INITIALIZE
;***************************************************************************
CF_INIT JSR CF_WT_BSY
 LDA #$E0
 STA >CF_LBA3
 JSR CF_WT_BSY
 LDA #$01
 STA >CF_FEATURE
 JSR CF_WT_BSY
 LDA #$EF ;SET FEATURES
 STA >CF_CMD
 JSR CF_WT_BSY
 RTS
;***************************************************************************
;CF_RD_CMD
;Function: Gets a sector (512 bytes) into RAM buffer.
;***************************************************************************   
CF_RD_CMD JSR CF_WT_RDY
 STA >CF_CMD
 ;JSR CF_WT_DRQ
 JSR CF_WT_BSY
 
 LDA >CF_STAT
 ANDA #ST_ERR
 BNE CF_RD_CMD
 LDX #DATA_BUF
 LDB #0
1 PSHS B
;2 JSR CF_WT_DRQ
;2 JSR CF_WT_BSY
; ANDA #ST_ERR
; BNE 3F
 LDA >CF_DATA
 LDB >CF_DATA
 STB ,X+
 STA ,X+
 PULS B
 DECB
 BNE 1B
 RTS
;WAIT BUSY=0
CF_WT_BSY PSHS A
1 LDA >CF_STAT
 ANDA #ST_BSY
 BNE 1B
 PULS A
 RTS
;WAIT BUSY=0,RDY=1
CF_WT_RDY PSHS A
1 LDA >CF_STAT
 ANDA #(ST_BSY+ST_RDY)
 EORA #ST_RDY
 BNE 1B
 PULS A
 RTS
;WAIT BUSY=0,DRQ=1
CF_WT_DRQ LDA >CF_STAT
 ANDA #(ST_BSY+ST_DRQ)
 EORA #ST_DRQ
 BNE 1B
 RTS
 
 
PRCRLF PSHS A,B
 SWI
 FCB PCRLF
 PULS A,B
 RTS
MSG1 FCC /CF Card Test/
 FCB CR,LF
 FCB EOT
-----------------------

メモリテスト2

前回のメモリチェックに、アドレス線のチェックと(ほぼ)全領域のチェックを追加してみました。
・アドレス線のチェック
 特開平6-110723を参考に作成
・全領域のチェック
 $1000~$1FFFに対し順に$55書込・ビットの反転・コンペアを行います。
 これを、$8Dを除く、$80~$FFページのすべてに行います。

イメージ 1

--------------------------
 ORG ROM2OF
 ;CHECK MAPPING
 LBSR INITMAP
 LEAX CHK1MSG,PCR
 SWI
 FCB PDATA1
 LDA #$80
LOOP1 STA >MAPTABLE
 STA >$0000
 INCA
 BNE LOOP1
 LDA #$80
LOOP2 STA >(MAPTABLE+1)
 CMPA >$1000
 LBNE PERRMSG
 INCA
 BNE LOOP2
 JSR POKMSG
 
 LBSR INITMAP 
 
 ;CHECK TASK
 LEAX CHK2MSG,PCR
 SWI
 FCB PDATA1
 LDB #$0
 LDA #$80
LOOP3 STB >UPDTASK
 STB >MAPTASK
 STA >MAPTABLE
 STA >$0000
 INCB
 INCA
 CMPB #8
 BCS LOOP3
 LDB #0
 STB >UPDTASK
 LDA #$80
LOOP4 STB >MAPTASK
 CMPA >$0000
 LBNE PERRMSG
 INCB
 INCA
 CMPB #8
 BCS LOOP4
 LBSR INITMAP
 JSR POKMSG
 
 ;CHECK RAM ADDRESS LINE
 ;特開平6-110723を参考に作成
 LEAX CHK3MSG,PCR
 SWI
 FCB PDATA
 ;ADDRESS LINE 00001-00800
 LDA #0
 STA >$0
 LDY >$ffe0
 LDA #$80
 STA ,Y
 LDX #$0001
LOOP5 LDA #$ff
 STA ,X
 LDB >$0
 LBNE PERRMSG
 TFR X,D
 LSLB
 ROLA
 TFR D,X
 CMPD #$1000
 BNE LOOP5
 ;ADDRESS LINE 01000-40000
 LDA #$81
 LDY #$ffe1
 LDX #$1000
LOOP6 STA ,Y
 LDB #$ff
 STB ,X
 LDB >$0
 BNE PERRMSG
 LSLA
 ORA #$80
 CMPA #$80
 BNE LOOP6
 BSR INITMAP
 JSR POKMSG
 
 ;RAM CHECK
 ;ALL AREA(without 0D000-0DFFF)
 LEAX CHK4MSG,PCR
 SWI
 FCB PDATA1
 
 LDA #$80
RCLOOP PSHS A
 LEAX ,S
 SWI
 FCB OUT2HS
 PULS A
 CMPA #$8D
 BEQ RCSKIP
 ;check
 STA >(MAPTABLE+1)
 LDX #$1000
RCCHKLOOP
 BSR CHK1BYT
 LBNE PRAMERR
 LEAX 1,X
 CMPX #$2000
 BNE RCCHKLOOP
 ;OK
 PSHS A
 LEAX RAMOK,PCR
 SWI
 FCB PDATA1
 PULS A
 BRA RCNEXT
 
RCSKIP PSHS A
 LEAX RAMSKIP,PCR
 SWI
 FCB PDATA1
 PULS A
RCNEXT INCA
 BNE RCLOOP
 BSR INITMAP
 LEAX RAMALOK,PCR
 SWI
 FCB PDATA1
 RTS
 
INITMAP ;reinitialize map
 LDA #$0
 STA >MAPTASK
 STA >UPDTASK
 LDA #$80
 LDX #$FFE0
IMLOOP STA ,X+
 INCA
 CMPA #$8E
 BNE IMLOOP
 RTS
POKMSG LEAX COKMSG,PCR
 SWI
 FCB PDATA1
 RTS
PERRMSG BSR INITMAP
 LEAX CERRMSG,PCR
 SWI
 FCB PDATA1
 RTS
PRAMERR BSR INITMAP
 LEAX RAMNG,PCR
 SWI
 FCB PDATA1
 RTS
PRCRLF SWI
 FCB PCRLF
 RTS
CHK1BYT LDB #$55
 STB ,X
 COM ,X
 COMB
 CMPB ,X
 BNE C1BRTS
 LDB #$AA
 STB ,X
 CMPB ,X
C1BRTS RTS
CHK1MSG FCC /CHECK MAPPING.../
 FCB EOT
CHK2MSG FCC /CHECK TASK.../
 FCB EOT
CHK3MSG FCC /CHECK ADDRESS LINE.../
 FCB EOT
CHK4MSG FCC /CHECK ALL RAM(Without 0D000-0DFFF).../
 FCB EOT
COKMSG FCC /OK/
 FCB CR,LF
 FCB EOT
CERRMSG FCC /ERROR/
 FCB CR,LF
 FCB EOT
RAMOK FCC /OK /
 FCB EOT
RAMNG FCC /NG/
 FCB CR,LF
 FCB EOT
RAMSKIP FCC /SKIP/
 FCB CR,LF
 FCB EOT
RAMALOK  FCB CR,LF
 FCC /RAM ALL OK/
 FCB EOT

メモリテスト

6809アセンブリ言語の勉強と合わせて、
1.メモリマッピング機能のテスト
・0000-0FFFに128ページ分のRAMを順番に割付し、個別の値($80~$FF)を書き込む。
・2000-2FFFに128ページ分のRAMを順番に割付し、書き込んだ値が読み出せることを確認する。

2.8タスク分のマッピングのテスト
・0~7のタスクに対し個別のページを0000-0FFFに割付し、個別の値を書き込む。
・0~7のタスクを選択し、個別に書き込んだ値が読み出せることを確認する。

簡単なプログラムを作成してみました。
ASSIST09から実行します。

イメージ 1


--------------------------
 ORG ROM2OF
 ;CHECK MAPPING
 LEAX CHK1MSG,PCR
 SWI
 FCB PDATA
 LDA #$80
LOOP1 STA >MAPTABLE
 STA >$0000
 INCA
 BNE LOOP1
 LDA #$80
LOOP2 STA >(MAPTABLE+1)
 CMPA >$1000
 BNE PERRMSG
 INCA
 BNE LOOP2
 LDA #$0
 
 JSR POKMSG
 ;CHECK TASK
 LEAX CHK2MSG,PCR
 SWI
 FCB PDATA
 LDB #$0
 LDA #$80
LOOP3 STB >UPDTASK
 STB >MAPTASK
 STA >MAPTABLE
 STA >$0000
 INCB
 INCA
 CMPB #8
 BCS LOOP3
 LDB #0
 STB >UPDTASK
 LDA #$80
LOOP4 STB >MAPTASK
 CMPA >$0000
 BNE PERRMSG
 INCB
 INCA
 CMPB #8
 BCS LOOP4
 
 JSR POKMSG
 
 RTS
POKMSG LEAX COKMSG,PCR
 SWI
 FCB PDATA
 RTS
PERRMSG LEAX CERRMSG,PCR
 SWI
 FCB PDATA
 RTS
CHK1MSG FCC /CHECK MAPPING.../
 FCB EOT
CHK2MSG FCC /CHECK TASK.../
 FCB EOT
COKMSG FCC /OK/
 FCB CR,LF
 FCB EOT
CERRMSG FCC /ERROR/
 FCB CR,LF
 FCB EOT
--------------------------

簡単なMMU実装完了

マッピングの実装ができました。
簡単なプログラムで簡単な動作確認もできました。

1.機能
・4kb単位でマッピング
・8タスク分のマップ情報を保持(LUT数の限界)
・FFD0:マッピング対象のタスク番号(0~7)
・FFD1:マッピング情報更新対象のタスク番号
・FFE0~FFEF:マッピング情報
 00~7F:ROM(SBC6809は8KBが最大なので00~01)
 80~FF:RAM(512KBまで可能)
2.動作確認用のBASICソース
8000~8FFFのマッピングを変更しています。
1000 POKE &HFFD0,0
1010 POKE &HFFD1,0
1020 PRINT "&H88"
1030 GOSUB 1160
1040 PRINT "&H90"
1050 POKE &HFFE8,&H90
1060 POKE &H8000,&HAA
1070 GOSUB 1160
1080 POKE &HFFE8,&H88
1090 PRINT "&H88"
1100 GOSUB 1160
1110 POKE &HFFE8,&H90
1120 PRINT "&H90"
1130 GOSUB 1160
1140 POKE &HFFE8,&H88
1150 END
1160 A=&H8000
1170 FOR J=0 TO 3
1180 PRINT RIGHT$("000"+HEX$(A),4);" ";
1190 FOR I=0 TO 15
1200 C=PEEK(A)
1210 PRINT RIGHT$("0"+HEX$(C),2);" ";
1220 A=A+1
1230 NEXT I
1240 PRINT
1250 NEXT J
1260 RETURN

3.動作画面
イメージ 1

①初期状態の8000~803Fのメモリダンプを表示
②8000~8FFFのマップを変更後、8000を書き換えし、メモリダンプを表示
③マップを初期状態に戻し、メモリダンプを表示
④再度、マップを変更し、メモリダンプを表示

4.FPGAソース
module MMU(a_in, d_in, e_in, rw_in, rd_in, wr_in, a_out, ce_out);
 input wire [15:0] a_in;
 input wire [7:0] d_in;
 input wire e_in;
 input wire rw_in;
 input wire rd_in;
 input wire wr_in;
 //A12-A19を返す
 output wire [7:0] a_out;
 //CEを返す
 //[0]:ROM
 //[1]:RAM
 //[2]:ACIA-1
 //[3]:ACIA-2
 //[4]:PTM
 //[5]:PIA
 //[6]:V9958
 output wire [7:0] ce_out;
 
 //FF80-FF8F:PTM
 //FF90-FF9F:ACIA-1(6850)
 //FFA0-FFAF:PIA
 //FFB0-FFBF:ACIA-2(6850)
 //FFC0-FFCF:V9958(予定)
 //FFD0:マッピング対象タスク(0-31)
 //FFD1:マッピングテーブル更新対象タスク(0-31)
 //FFE0-FFEF:マッピングテーブル(WriteOnly)
 
 reg [7:0] map [0:127];
 reg [2:0] sel_task;//現在選択しているタスク
 reg [2:0] upd_task;//マップテーブルを更新するタスク
 reg [7:0] a_out_r;
 reg [7:0] ce_out_r;
 reg [9:0] i;
 reg [6:0] index;
 
 initial begin
  sel_task = 0;
  upd_task = 0;
  for (i=0; i<128; i=i+16) begin
   //初期メモリ設定
   map[i+0] = 8'h80;//0000:RAM
   map[i+1] = 8'h81;//1000:RAM
   map[i+2] = 8'h82;//2000:RAM
   map[i+3] = 8'h83;//3000:RAM
   map[i+4] = 8'h84;//4000:RAM
   map[i+5] = 8'h85;//5000:RAM
   map[i+6] = 8'h86;//6000:RAM
   map[i+7] = 8'h87;//7000:RAM
   map[i+8] = 8'h88;//8000:RAM
   map[i+9] = 8'h89;//9000:RAM
   map[i+10] = 8'h8a;//a000:RAM
   map[i+11] = 8'h8b;//b000:RAM
   map[i+12] = 8'h8c;//c000:RAM
   map[i+13] = 8'h8d;//d000:RAM
   map[i+14] = 8'h00;//e000:ROM
   map[i+15] = 8'h01;//f000:ROM
  end
 end
 
 function [7:0] CE(
  input [15:0] in_address,
  input [7:0] out_address
 );
 
  case (in_address[15:4])
  12'hff8:
   //FF80-FF8F:PTM
    CE = 8'b11101111;
  12'hff9:
   //FF90-FF9F:ACIA-1(6850)
    CE = 8'b11111011;
  12'hffa:
   //FFA0-FFAF:PIA
    CE = 8'b11011111;
  12'hffb:
   //FFB0-FFBF:ACIA-2(6850)
    CE = 8'b11110111;
  12'hffc:
   //FFC0-FFCF:V9958
    CE = 8'b10111111;
  12'hffd:
   //FFD0-FFDF:MMU:CEはすべてHIGH
    CE = 8'b11111111;
  12'hffe:
   //FFE0-FFEF:MMU:CEはすべてHIGH
    CE = 8'b11111111;
  12'hfff:
   //FFF0-FFFF:ROM
    CE = 8'b11111110;
  default:
   begin
    //最上位bitが0の場合はROM
    if (out_address[7] == 1'b0)
      CE = 8'b11111110;
    else
      CE = 8'b11111101;
   end
  endcase
 endfunction
 
 //アドレス変換、および、CE出力
 always @(a_in) begin
  a_out_r <= map[{sel_task,a_in[15:12]}];
  ce_out_r <= CE(a_in, map[{sel_task,a_in[15:12]}]);
 end
 
 //FFD0-FFEF:MMU用のI/O
 always @(posedge e_in) begin
  //eの立下りで取り込む
  if(rw_in == 1'b0) begin
   if(a_in[15:0] == 16'hffd0) begin
    //FF80:マッピング対象タスク選択
    sel_task <= d_in[2:0];
   end else if(a_in[15:0] == 16'hffd1) begin
    //FF81:マッピングテーブル更新対象タスク選択
    upd_task <= d_in[2:0];
   end else if(a_in[15:4] == 12'hffe) begin
    //FF90-FF9Fマッピングテーブル更新
    map[{upd_task,a_in[3:0]}] <= d_in;
   end
  end
 end
 
 assign ce_out = ce_out_r;
 assign a_out = a_out_r;
endmodule