目次

ROMエミュレータ作成

 アセンブリ言語、C言語で作ったファームウエアを
 ROMに焼き、動作テストするための時間が勿体なく
 思えてきたので、ROMエミュレータを作成しました。



 SRAMは、秋月電子で32kバイトのチップ5個で\300程度
 なので、変換基板と合わせて入手してありました。
 今回、このSRAMを利用することに。



 ROMエミュレータの内容は、非常に簡単で、次のブロック図
 に相当するレジスタを入れてあります。



 2つのCPLDに、4ビットレジスタを複数用意しておき
 アドレスデコーダを利用して、各レジスタに値を設定
 します。CPLDを使うのは、手持ちのロジックICがない
 のと、後で回路を変更しやすくするため。

 8ビットのうち上位4ビットをアドレスに、下位4ビットを
 データにして、4ビットレジスタにデータを格納します。

 アドレスとレジスタの組合せは、以下。

 nHiZは、CPLDの出力をハイインピーダンス状態にします。

 nRESETは、CPUやMPUをリセット状態にし、アドレス、データ
 制御バスをハイインピーダンス状態にします。
 nCS,nWRは、SRAMにアドレス、データを指定してデータを
 格納するために利用。

 TTLロジックの回路図で示すと、次のようになります。



 2つのCPLDに、ブロック図に相当するデジタル回路をVHDL言語
 で記述して、入れました。VHDLコードは、以下。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity romemu is
  port (
    -- system 
    nRESET : in  std_logic;
    CLOCK  : in  std_logic;
    -- input trigger
    TRG    : in  std_logic ;
    -- selector
    SEL    : in  std_logic_vector(3 downto 0);
    -- input data
    NDAT   : in  std_logic_vector(3 downto 0);
    -- output
    ROUT1  : out std_logic_vector(7 downto 0);
    ROUT0  : out std_logic_vector(7 downto 0)-- ;
  );
end romemu;

architecture behavioral of romemu is
  -- trigger
  signal iTRG_SFT : std_logic_vector(2 downto 0);
  signal iTRG     : std_logic ;
  -- internal registers
  signal iREG0 : std_logic_vector(7 downto 0);
  signal iREG1 : std_logic_vector(7 downto 0);
  signal iREGX : std_logic ;
  -- sequence
  signal iSTATE : std_logic_vector(1 downto 0);
  signal iSEL   : integer range 0 to 15 ;
  signal iNDAT  : std_logic_vector(3 downto 0);
begin
  -- input
  iNDAT <= NDAT ;

  -- output
  ROUT1 <= iREG0 when ( iREGX = '1' ) else (others => 'Z') ;
  ROUT0 <= iREG1 when ( iREGX = '1' ) else (others => 'Z') ;

  -- trigger
  process(nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iTRG_SFT <= "000" ;
    elsif rising_edge( CLOCK ) then
      iTRG_SFT <= iTRG_SFT(1 downto 0) & TRG ;
    end if;
  end process;
  iTRG <= '1' when ( iTRG_SFT = "011" ) else '0' ;

  -- master sequencer
  process( nRESET , CLOCK )
  begin
    if ( nRESET = '0' ) then
      iREG0  <= (others => '0') ;
      iREG1  <= (others => '0') ;
      iREGX  <= '0' ;
      iSTATE <= "00" ;
      iSEL   <= 0 ;
    elsif rising_edge( CLOCK ) then
      case conv_integer(iSTATE) is
       -- wait trigger 
       when 0 => if ( iTRG = '1' ) then
                   iSTATE <= "01" ;
                 else
                   iSTATE <= "00" ;
                 end if ;
       -- latch data
       when 1 => iSTATE <= "11" ;
                 iSEL   <= conv_integer(SEL) ;
       -- deliver
       when 3 => iSTATE <= "10" ;
                 if ( iSEL = 0 ) then
                   iREG0(3 downto 0) <= iNDAT ;
                 end if ;
                 if ( iSEL = 1 ) then
                   iREG0(7 downto 4) <= iNDAT ;
                 end if ;
                 if ( iSEL = 2 ) then
                   iREG1(3 downto 0) <= iNDAT ;
                 end if ;
                 if ( iSEL = 3 ) then
                   iREG1(7 downto 4) <= iNDAT ;
                 end if ;
                 if ( iSEL > 7 ) then
                   iREGX <= iNDAT(0) ;
                 end if ;
       -- return first state
       when 2 => iSTATE <= "00" ;
       -- default
       when others =>
                 iSTATE <= "00" ;
      end case ;
    end if;
  end process;

end behavioral;

 内部に8ビットレジスタを2本、1ビットレジスタを
 ひとつ用意します。STROBE信号は、シフトレジスタで
 受け、内部のトリガーとします。

 レジスタに確実にデータを格納するため
 シーケンサを利用します。

 ピンアサインは、以下。

NET "CLOCK"  LOC = "P5";
NET "nRESET" LOC = "P39";

# control
NET "NDAT<0>" LOC = "P24";
NET "NDAT<1>" LOC = "P25";
NET "NDAT<2>" LOC = "P26";
NET "NDAT<3>" LOC = "P27";
NET "SEL<0>"  LOC = "P28";
NET "SEL<1>"  LOC = "P29";
NET "SEL<2>"  LOC = "P33";
NET "SEL<3>"  LOC = "P34";

# trigger
NET "TRG"     LOC = "P36";
NET "TLED"    LOC = "P35";

# data
NET "ROUT0<0>"  LOC = "P1" ;
NET "ROUT0<1>"  LOC = "P2" ;
NET "ROUT0<2>"  LOC = "P3" ;
NET "ROUT0<3>"  LOC = "P4" ;
NET "ROUT0<4>"  LOC = "P6" ;
NET "ROUT0<5>"  LOC = "P7" ;
NET "ROUT0<6>"  LOC = "P8" ;
NET "ROUT0<7>"  LOC = "P9" ;

# data
NET "ROUT1<0>" LOC = "P11";
NET "ROUT1<1>" LOC = "P12";
NET "ROUT1<2>" LOC = "P13";
NET "ROUT1<3>" LOC = "P14";
NET "ROUT1<4>" LOC = "P18";
NET "ROUT1<5>" LOC = "P19";
NET "ROUT1<6>" LOC = "P20";
NET "ROUT1<7>" LOC = "P22";

 PersonalComputerのパラレルポートから、SRAMにデータを
 転送することを想定して使います。パラレルポートを持つ
 ノートPCを使って、SRAMにデータ転送します。

 ノートPCは、Windows3.1かWindows98をOS
 として載せているマシンを利用。



 このマシンで、MS-DOSで動作するROMエミュレータ
 用ソフトを作成し、梅澤無線電機のUECを基板上に
 実装して使います。

 ROMエミュレータを利用した、ファームウエア開発は
 次のような開発環境になした。



 SRAMのアドレス、データはZ80、CPLDどちらも出力し
 nWEはCPLDのみ、nOEはZ80のみが出力します。
 アドレス、データは、ハイインピーダンスになる
 よう、制御して対応します。



 ROMエミュレータが内蔵しているSRAM(32kバイト)に
 プログラムを転送するには、LSICでアプリケーション
 を作成して対応。

 MS-DOSが動作していれば、パラレルポートは次の
 どこかのI/Oアドレスに割当てられています。
    0378h
    0278h
    03BCh

 上の3ポートのアドレスは、データ入出力の8ビット
 アドレスです。制御は、STORBE信号をON/OFFするので
 上のI/Oアドレスに、オフセットの+2を加えた、制御
 レジスタにパラメータを設定。

 ROMエミュレータへ、1バイトデータを転送
 するには、次のタイミングチャートを利用。



 1バイトのデータを出力し、STROBE信号をON/OFFしますが
 データのセットアップタイム、ホールタイムを満たすよう
 にしなければなりません。PersonalComputerに使われている
 チップにもよりますが、1usの単位で動くので、気にせずに
 処理してよいでしょう。

 パラレルポートのチェックをするために、次の基板を
 利用しました。74HC574のD入力にPD0〜PD7に、CLOCKに
 STROBEを接続しています。Q出力にLEDを接続しました。



 データ出力のテストプログラムは、非常に簡単です。
 LEDに0〜255に相当する点灯パターンを転送して
 いるだけです。(このプログラムは、LSICで作成して
 あります。)

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <io.h>

#define LPT1 0x378
#define LPT2 0x3bc
#define LPT3 0x278

int lpt_address ;

int set_address(int adr)
{
  /* error check */
  if ( adr < 0 || 255 < adr ) return -1 ;
  /* address */
  outp(lpt_address,adr);
  /* strobe */
  outp(lpt_address+2,0xc4);
  outp(lpt_address+2,0xcc);
  outp(lpt_address+2,0xcd);
  outp(lpt_address+2,0xcc);
  outp(lpt_address+2,0xc4);
  /* result */
  return 0 ;
}

int set_data(int adr,int dat)
{
  /* error check */
  if ( set_address(adr) == -1 ) return -1 ;
  if ( dat < 0 || 255 < dat ) return -1 ;
  /* data */
  outp(lpt_address,dat);
  /* strobe */
  outp(lpt_address+2,0xc4);
  outp(lpt_address+2,0xc6);
  outp(lpt_address+2,0xc7);
  outp(lpt_address+2,0xc6);
  outp(lpt_address+2,0xc4);
  /* result */
  return 0 ;
}

void xwait(void)
{
  unsigned short x,i ;

  for ( i = 0 ; i < 200 ; i++ ) {
    x = 0xffff ;
    while ( x ) { x-- ; }
  }
}

int main(int argc,char *argv[])
{
  int i,address,lpt_num ;

  /* usage */
  if ( argc != 3 ) {
    fprintf(stderr,"Usage:ledz lpt_num address\n");
    exit(1);
  }

  /* judge */
  address = atoi( &argv[2][0] ) ;
  if ( address < 0 || 255 < address ) {
    fprintf(stderr,"address range 0 <-> 255\n");
    exit(1);
  }
  lpt_num = atoi( &argv[1][0] ) ;
  if ( lpt_num < 1 || 3 < lpt_num ) {
    fprintf(stderr,"lpt_number range 1 <-> 3\n");
    exit(1);
  }
  lpt_address = LPT1 ; 
  if ( lpt_num == 2 ) { lpt_address = LPT2 ; }
  if ( lpt_num == 3 ) { lpt_address = LPT3 ; }
  /* endless loop */
  i = 0 ;
  while ( 1 ) {
    /* get keyboard */
    if ( kbhit() ) break ;
    /* out data */
    set_data(address,i);
    xwait();
    /* update */
    i++ ;
    i %= 256 ;
  }
  set_data(address,0x00);

  return 0 ;
}

 パラレルポートにデータを転送できることを
 確認した後、次のプログラムを作成してROM
 エミュレータ上のSRAMにデータ転送します。

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <io.h>

typedef unsigned char  UBYTE ;
typedef unsigned short UWORD ;

#define LPT1 0x378
#define LPT2 0x3bc
#define LPT3 0x278

#define MASKFF 0xff
#define MASK0F 0x0f

#define OFF 0
#define ON  OFF+1

#define DISABLE_RESET 0
#define ENABLE_RESET  1

#define DISABLE_HIZ 0
#define ENABLE_HIZ  1

#define STB_OFF 0xcc
#define STB_ON  0xcd

#define CSOFF_WEOFF 0x03
#define CSON_WEOFF  0x01
#define CSON_WEON   0x00

#define CON_ADR0 0x00
#define CON_ADR1 0x10

#define DAT_LNIBBLE 0x20
#define DAT_HNIBBLE 0x30

#define ADRL_LNIBBLE 0x40
#define ADRL_HNIBBLE 0x50

#define ADRH_LNIBBLE 0x40
#define ADRH_HNIBBLE 0x50

#define CON_ADR0 0x00
#define CON_ADR1 0x10

UWORD lpt_address ;

void  send_primitive(UBYTE x);
void  send_write_pulse(void);
void  send_reset(UBYTE x);
void  send_hiz(UBYTE x);
void  send_dat(UWORD ax,UBYTE dx);
void  send_control(UBYTE dx);
UBYTE get_hex(UBYTE x);

int main(int argc,char *argv[])
{
  FILE  *fin ;
  UWORD lpt_num ;
  UWORD madr ;
  UBYTE mdat ;
  UBYTE mtype ;
  UBYTE mcnt ;
  UBYTE mindex ;
  UBYTE loop ;
  char  mbuf[256] ;

  /* usage */
  if ( argc != 3 ) {
    fprintf(stderr,"Usage:romemu lpt_num hex_file_name\n");
    exit(1);
  }

  lpt_num = atoi( &argv[1][0] ) ;
  if ( lpt_num < 1 || 3 < lpt_num ) {
    fprintf(stderr,"lpt_number range 1 <-> 3\n");
    exit(1);
  }
  lpt_address = LPT1 ; 
  if ( lpt_num == 2 ) { lpt_address = LPT2 ; }
  if ( lpt_num == 3 ) { lpt_address = LPT3 ; }

  fin = fopen(&argv[2][0],"r") ;
  if ( fin == NULL ) {
    fprintf(stderr,"file not exist !\n");
    exit(1);
  }
  /* CPLD access SRAM */
  send_reset(ENABLE_RESET);
  send_hiz(DISABLE_HIZ);
  /* store data to ROM emulator */
  madr = 0 ;
  mcnt = 0 ;
  mtype = 0 ;
  while ( !feof(fin) ) {
    /* get 1 line */
    fgets(mbuf,256,fin);
    /* judge */
    if ( *(mbuf+0) != ':' ) continue ;
    /* fprintf(stdout,"%s",mbuf); */
    /* counter */
    mcnt  = get_hex( *(mbuf+1) ); mcnt <<= 4 ;
    mcnt += get_hex( *(mbuf+2) );
    /* address */
    madr  = get_hex( *(mbuf+3) ); madr <<= 4 ;
    madr += get_hex( *(mbuf+4) ); madr <<= 4 ;
    madr += get_hex( *(mbuf+5) ); madr <<= 4 ;
    madr += get_hex( *(mbuf+6) );
    /* type */
    mtype  = get_hex( *(mbuf+7) ); mtype <<= 4 ;
    mtype += get_hex( *(mbuf+8) );
    /* judge */
    if ( mtype != 0 ) continue ;
    /* loop */
    for ( loop = 0 ; loop < mcnt ; loop++ ) {
      /* calcualte pointer */
      mindex = 9 + loop * 2 ;
      /* get data */
      mdat  = get_hex( *(mbuf+mindex) ) ; mdat <<= 4 ;
      mdat += get_hex( *(mbuf+mindex+1) );
      /* transfer */
      send_dat(madr,mdat);
    }
    putchar('\n');
  }
  /* close file */
  fclose( fin );
  /* CPU access SRAM */
  send_hiz(ENABLE_HIZ);
  send_reset(DISABLE_RESET);

  return 0 ;
}

void send_primitive(UBYTE x)
{
  /* impress data */
  outp(lpt_address,x);
  /* strobe handling */
  outp(lpt_address+2,STB_OFF);
  outp(lpt_address+2,STB_ON );
  outp(lpt_address+2,STB_OFF);
}

void send_write_pulse(void)
{
  /* enable nCS */
  send_primitive(CON_ADR0 | CSON_WEOFF);
  /* enable nWR */
  send_primitive(CON_ADR0 | CSON_WEON);
  /* disable nWR */
  send_primitive(CON_ADR0 | CSON_WEOFF);
  /* disable nCS */
  send_primitive(CON_ADR0 | CSOFF_WEOFF);
}

void send_reset(UBYTE x)
{
  if ( x ) { send_primitive(CON_ADR1 | OFF); }
  else     { send_primitive(CON_ADR1 | ON ); }
}

void send_hiz(UBYTE x)
{
  if ( x ) { send_primitive(0x80 | ON ); }
  else     { send_primitive(0x80 | OFF); }
}

void send_dat(UWORD ax,UBYTE dx)
{
  UBYTE tmpx ;
  /* get upper address and put */
  tmpx = (ax >> 8) & MASKFF ;
  send_primitive(ADRH_HNIBBLE | ((tmpx >> 4) & MASK0F));
  send_primitive(ADRH_LNIBBLE | (tmpx & MASK0F));
  /* get lower address and put */
  tmpx = ax & MASKFF ;
  send_primitive(ADRL_HNIBBLE | ((tmpx >> 4) & MASK0F));
  send_primitive(ADRL_LNIBBLE | (tmpx & MASK0F));
  /* get data and put */
  tmpx = dx ;
  send_primitive(DAT_HNIBBLE | ((tmpx >> 4) & MASK0F));
  send_primitive(DAT_LNIBBLE | (tmpx & MASK0F));
  /* store */
  send_write_pulse();
}

void send_control(UBYTE dx)
{
  send_primitive( dx );
}

UBYTE get_hex(UBYTE x)
{
  UBYTE result ;
  /* default */
  result = 0 ;
  /* judge */
  if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
  if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
  if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }

  return result ;
}

 やっていることは、非常に単純です。

 パラレルポートのアドレスを1〜3のどれかで指定し
 ROMに転送したいHEXファイルから、1バイトずつSRAM
 にデータを送っているだけ。

 パラレルポートのアドレスは、以下のように決めました。

 使うときは、次のようにします。
    romenu 1 test.hex{enter}

 テスト用に作成したHEXファイルのソースコードは
 PIOAから入力したデータを、PIOBに出力する処理
 を使います。

CTC0  EQU 10h
CTC1  EQU 11h
CTC2  EQU 12h
CTC3  EQU 13h
SIOAD EQU 18h
SIOAC EQU 19h
SIOBD EQU 1ah
SIOBC EQU 1bh
PIOAD EQU 1ch
PIOAC EQU 1dh
PIOBD EQU 1eh
PIOBC EQU 1fh

  org 0h
  ld  sp,0h
  jp  START

  org 100h
START:
  ; initialize hardware
  call  INIT

;***********
; echo back 
;***********
MAIN:
  ; get data from PIOA
  in  a,(PIOAD)
  ; put data tor PIOB
  out (PIOBD),a
  ;
  jr  MAIN

;**********************
; initialize hardware
;**********************
INIT:
  ; initialize PIO
  call  INIT_PIO
  ;
  ret

;****************
; initialize PIO 
;****************
INIT_PIO:
  ;
  push af
  ; PIOA (input mode)
  ld   a,4fh
  out (PIOAC),a
  ; turn off all LEDs
  ld   a,00h
  out  (PIOBD),a
  ; PIOB (output mode)
  ld   a,0fh
  out  (PIOBC),a
  ;
  pop  af
  ret

  END

 Z80を動かすには、Z80のnRESETを'L'から'H'にします。

 nRESET='L'のとき、Z80はアドレス、データ線をハイ
 インピーダンスにするので、ROMエミュレータにある
 SRAMをCPLDがアクセスするなら、Z80からの制御信号
 を切断して対応します。



 Z80からは、ROMエミュレータ上のSRAMはリードさえ
 出来ればよいので、上の回路でメモリリードだけが
 可能となる仕掛けを作ります。
 nRESET信号は、CPLDから出力します。

 利用するCPLDに、空き容量があったので、上の
 回路を入れました。

 VHDLコードは、以下です。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity romemu is
  port (
    -- system 
    nRESET : in  std_logic;
    CLOCK  : in  std_logic;
    -- input trigger
    TRG    : in  std_logic ;
    -- selector
    SEL    : in  std_logic_vector(3 downto 0);
    -- input data
    NDAT   : in  std_logic_vector(3 downto 0);
    -- input MREQ and RD
    nMREQ   : in  std_logic ;
    nRD     : in  std_logic ;
    nXRESET : in  std_logic ;
    -- monitor output
    TLED   : out std_logic ;
    --
    nMRD   : out std_logic ;
    -- output
    ROUT1  : out std_logic_vector(7 downto 0);
    ROUT0  : out std_logic_vector(7 downto 0)-- ;
  );
end romemu;

architecture behavioral of romemu is
  -- trigger
  signal iTRG_SFT : std_logic_vector(2 downto 0);
  signal iTRG     : std_logic ;
  -- internal registers
  signal iREG0 : std_logic_vector(7 downto 0);
  signal iREG1 : std_logic_vector(7 downto 0);
  signal iREGX : std_logic ;
  -- sequence
  signal iSTATE : std_logic_vector(1 downto 0);
  signal iSEL   : integer range 0 to 15;
  signal iNDAT  : std_logic_vector(3 downto 0);
  -- 
  signal iMRD : std_logic ;
begin
  -- monitor output
  TLED <= not iREGX ;

  nMRD <= iMRD when ( nXRESET = '1' ) else 'Z' ;

  -- input
  iNDAT <= NDAT ;

  -- output
  ROUT1 <= iREG0 when ( iREGX = '1' ) else (others => 'Z') ;
  ROUT0 <= iREG1 when ( iREGX = '1' ) else (others => 'Z') ;

  iMRD <= nMREQ or nRD ;

  -- trigger
  process(nRESET,CLOCK)
  begin
    if ( nRESET = '0' ) then
      iTRG_SFT <= "000" ;
    elsif rising_edge( CLOCK ) then
      iTRG_SFT <= iTRG_SFT(1 downto 0) & TRG ;
    end if;
  end process;
  iTRG <= '1' when ( iTRG_SFT = "011" ) else '0' ;

  -- master sequencer
  process( nRESET , CLOCK )
  begin
    if ( nRESET = '0' ) then
      iREG0  <= (others => '0') ;
      iREG1  <= (others => '0') ;
      iREGX  <= '0' ;
      iSTATE <= "00" ;
      iSEL   <= 0 ;
    elsif rising_edge( CLOCK ) then
      case conv_integer(iSTATE) is
       -- wait trigger 
       when 0 => if ( iTRG = '1' ) then
                   iSTATE <= "01" ;
                 else
                   iSTATE <= "00" ;
                 end if ;
       -- latch data
       when 1 => iSTATE <= "11" ;
                 iSEL   <= conv_integer(SEL) ;
       -- deliver
       when 3 => iSTATE <= "10" ;
                 if ( iSEL = 0 ) then
                   iREG0(3 downto 0) <= iNDAT ;
                 end if ;
                 if ( iSEL = 1 ) then
                   iREG0(7 downto 4) <= iNDAT ;
                 end if ;
                 if ( iSEL = 2 ) then
                   iREG1(3 downto 0) <= iNDAT ;
                 end if ;
                 if ( iSEL = 3 ) then
                   iREG1(7 downto 4) <= iNDAT ;
                 end if ;
                 if ( iSEL > 7 ) then
                   iREGX <= iNDAT(0) ;
                 end if ;
       -- return first state
       when 2 => iSTATE <= "00" ;
       -- default
       when others =>
                 iSTATE <= "00" ;
      end case ;
    end if;
  end process;

end behavioral;

 ピン割当ては、次のようにしました。

NET "CLOCK"  LOC = "P5";
NET "nRESET" LOC = "P39";

# control
NET "NDAT<0>" LOC = "P24";
NET "NDAT<1>" LOC = "P25";
NET "NDAT<2>" LOC = "P26";
NET "NDAT<3>" LOC = "P27";
NET "SEL<0>"  LOC = "P28";
NET "SEL<1>"  LOC = "P29";
NET "SEL<2>"  LOC = "P33";
NET "SEL<3>"  LOC = "P34";

# trigger
NET "TRG"     LOC = "P36";
NET "TLED"    LOC = "P35";

# data
NET "ROUT0<0>"  LOC = "P1" ;
NET "ROUT0<1>"  LOC = "P2" ;
NET "ROUT0<2>"  LOC = "P3" ;
NET "ROUT0<3>"  LOC = "P4" ;
NET "ROUT0<4>"  LOC = "P6" ;
NET "ROUT0<5>"  LOC = "P7" ;
NET "ROUT0<6>"  LOC = "P8" ;
NET "ROUT0<7>"  LOC = "P9" ;

# data
NET "ROUT1<0>" LOC = "P11";
NET "ROUT1<1>" LOC = "P12";
NET "ROUT1<2>" LOC = "P13";
NET "ROUT1<3>" LOC = "P14";
NET "ROUT1<4>" LOC = "P18";
NET "ROUT1<5>" LOC = "P19";
NET "ROUT1<6>" LOC = "P20";
NET "ROUT1<7>" LOC = "P22";

#
NET "nMRD"    LOC = "P44" ;
NET "nMREQ"   LOC = "P43" ;
NET "nRD"     LOC = "P42" ;
NET "nXRESET" LOC = "P40" ;

 ROMエミュレータは、基板に実装したので、UECかAKI80を
 同じ基板に載せて、動かすようにします。今回は、梅澤
 無線のUECを、同じ基板に載せます。

 UECは、50ピンのコネクタを2つ利用するだけに対して
 AKI80は、26ピン、20ピンを使うので、半田付けが面倒
 だったことが理由です。

 UECには、基板上のROM、RAMを殺して、外部のROM、RAMを
 利用するための制御端子があるので、これを使えるのも
 魅力でした。

 ROMエミュレータの実体はSRAMなので、ROMを殺して
 このSRAMをROMに見せるカラクリが用意されている
 UECは、制御用としてAKI80にはない設計思想が見え
 ます。

 メモリ空間に関連する信号ピン割当ては、以下と
 なっています。

 1 RAMINH   2 ROMINH
 3 nINT     4 nHALT
 5 nMREQ    6 nIORQ
 7 nRD      8 nWR
 9 nBUSAK  10 nWAIT
11 nBUSRQ  12 nRESET
13 nM1     14 nRFSH
15  A1     16  A0
17  A3     18  A2
19  A5     20  A4
21  A7     22  A6
23  A9     24  A8
25 A11     26 A10
27 A13     28 A12
29 A15     30 A14
31  D0     32  D1
33  D2     34  D3
35  D4     36  D5
37  D6     38  D7
39 BACKUP  40 CLKOUT
41 nNMI    42 A7RF
43 IEO     44 IEI
45 nWDTOUT 46 nEXRESET
47 EV      48 GND
49 Vcc     50 Vcc

 制御は、5、7、8に出ている信号を利用し
 アドレスは15から30、データは31から38の
 ピンとメモリを接続することに。

 I/O処理も必要なので、どのような信号が出て
 いるのかを確認します。

 1 Vcc       2 GND
 3 CLK/TRG0  4 CLK/TRG1
 5 CLK/TRG2  6 CLK/TRG3
 7 TC/TO3    8 TC/TO2
 9 TC/TO1   10 TC/TO0
11 BRDY     12 nBSTB
13 PB7      14 PB6
15 PB5      16 PB4
17 PB3      18 PB2
19 PB1      20 PB0
21 nW/RDYB  22 nSYNCB
23 RxDB     24 nRxCB
25 nTxCB    26 nRSTB
27 nDTRB    28 TxDB
29 nCTSB    30 nDCDB
31 nDCDA    32 nCTSA
33 TxDA     34 nDTRA
35 nRTSA    36 TxCA
37 nRxCA    38 RxDA
39 nSYNCA   40 nW/RDYA
41 PA0      42 PA1
43 PA2      44 PA3
45 PA4      46 PA5
47 PA6      48 PA7
49 nASTB    50 ARDY


 パラレルI/Oは、A、Bチャネルあるので
 STBとRDYを直結し、単純I/Oとして使い
 ます。

 シリアルインタフェースは、3線式で
 使うこととし、RTSとCTS、DTRとDCDを
 直結します。

 シリアルインタフェースには、クロックが
 必要なので、TxC、RxCを直結します。
 タイマーカウンタの出力をTxC、RxCに接続
 して、外部クロックジェネレータを設けない
 ことに。

 TxD、RxDは、次のようにトランジスタを利用し
 論理レベルと論理値を反転します。
 (小信号トランジスタなら、何でもOK)



(under construction)

目次

inserted by FC2 system