ロジックICでスタック作った

ロジックICの組み合わせでスタックを作りました。スタックとはコンピュータで用いられるデータの保存方式の一つで後入れ先出し方式の構造を持っているものです。

制作中の自作CPUに組み込まれていますが今回はその前段階にブレッドボード上で実験した様子を動画にしてみました。

niconico

ロジックICでスタック作ってみた【電子工作】 - ニコニコ動画

youtube

 

youtu.be

pingは応答するがNASに接続できない

ルータを使ってNASを構築したんですが。

うちのパソコンのうちの1台だけエクスプローラからNASにアクセスできないという

問題が発生しました。エクスプローラのアドレス欄にIPアドレスを\\XXX.XXX.XXX.XXXと指定してのアクセスができない状態です。解決方法をメモしておきます。

以下の記事を参考にさせて頂いて解決しました。

http://capacitor.blog.fc2.com/blog-entry-352.html?sp

  1. コントロールパネルを開く
  2. プログラム
  3. windowsの機能の有効化または無効化
  4. "SMB 1.0/CIFSファイル共有のサポート"の欄にチェックを入れる
  5. 再起動する。

RX220 E2データフラッシュ 使い方

RX220のE2データフラッシュを使用するためのコードを書いたので公開します。といってもルネサス公式のサンプルプログラムそのままですが。これにより電源を落としてもE2データフラッシュに書き込んだデータなら保持することができるようになります。

自分の環境ではRXにプログラムを書き込むとROM内が消去されるみたいです。

ROMに書き込みや消去を行うにはそれなりに時間がかかるのでdelay関数をつくる必要があります。

18/3/16追記 E2ROM.cに一部バグがありました。修正済みです。

https://elearning.renesas.com/pluginfile.php/355/mod_folder/content/0/RX_MCU_Japanese/RX62N_FLD.pdf?forcedownload=1

 

E2ROM.h

#ifndef E2ROM_H_
#define E2ROM_H_

#include "iodefine.h"
#include "stdint.h"

enum status {FLD_ERROR,FLD_OK,FLD_TMOUT,FLD_BLANK,FLD_NOBLANK};

int wait_FRDY(unsigned int wait);//処理待ち関数
static void reset_fcu(void);//fcuリセット関数
int32_t fld_init_pclk_notification(void);//クロック通知関数
int32_t fld_blank_check_2KB( uint32_t addr );//ブランクチェック関数
int32_t fld_erase_2KB( uint32_t addr );//消去関数
int32_t fld_program_2byte( uint32_t addr, uint16_t *ram );//2byte書き込み関数
int32_t fld_program_8byte( uint32_t addr, uint16_t *ram );//8byte書き込み関数
int32_t fld_enable_read(void);//読み出し許可関数
int32_t fld_enable_PE(void);//読み出し無効PE有効

#endif /* E2ROM_H_ */

 

E2ROM.c

#include "E2ROM.h"

int32_t fld_init_pclk_notification(void)
{
	// 00100000h is top address of DB00 block
	volatile uint8_t *addr_b = (uint8_t *)0x00100000;
	volatile uint16_t *addr_w = (uint16_t *)0x00100000;
	// change to P/E mode
	if( (FLASH.FENTRYR.WORD & 0x00ff) != 0x0080 ){
		FLASH.FENTRYR.WORD = 0xAA80; // AAh is key
	}
	// set peripheral clock
	FLASH.PCKAR.BIT.PCKA = 32; // PCLK = 32 MHz
	// execute the peripheral clock notification command
	*addr_b = 0xE9;
	*addr_b = 0x03;
	*addr_w = 0x0F0F;
	*addr_w = 0x0F0F;
	*addr_w = 0x0F0F;
	*addr_b = 0xD0;
	// wait for tPCKA time
	if( wait_FRDY( 120 ) == FLD_TMOUT ){ // timeout is 120us
		reset_fcu();
	}
	// error check
	if( FLASH.FSTATR0.BIT.ILGLERR == 1 ){
		return FLD_ERROR;
	}
	return FLD_OK;
}


int32_t fld_blank_check_2KB( uint32_t addr )
{
	volatile uint8_t *addr_b = (uint8_t *)addr;
	// use the blank checking command
	FLASH.FMODR.BIT.FRDMD = 1;
	// set the blank check size (2 KB)
	FLASH.DFLBCCNT.BIT.BCSIZE = 1;
	// execute the Blank checking command
	*addr_b = 0x71;
	*addr_b = 0xD0;
	// wait for tDBC2K time (timeout is 770us)
	if( wait_FRDY( 700*1.1 ) == FLD_TMOUT ){
		reset_fcu();
	}
	// error check
	if( FLASH.FSTATR0.BIT.ILGLERR == 1 ){
		return FLD_ERROR;
	}
	// get result of blank checking command
	if( FLASH.DFLBCSTAT.BIT.BCST == 0 ){
		return FLD_BLANK;
	}
	return FLD_NOBLANK;
}

int32_t fld_erase_2KB( uint32_t addr )
{
	volatile uint8_t *addr_b;
	int32_t ret = FLD_OK;
	int i=0;
	// Unprotect
	FLASH.FWEPROR.BIT.FLWE = 1;
	// enable to erase all blocks
	FLASH.DFLWE0.WORD = 0x1E0F; // 1Eh is Key
	for(i=0;i<16;i++){
		addr_b = (uint8_t *)((uint32_t)addr + (uint32_t)128*i);//消去ブロックを移動
		// execute the block erase command
		*addr_b = 0x20;
		*addr_b = 0xD0;
		// wait for tDE2K time (timeout is 275ms)
		if( wait_FRDY( 250*1000*1.1 ) == FLD_TMOUT ){
			reset_fcu();
		}
		// Error check
		if( (FLASH.FSTATR0.BIT.ILGLERR == 1) ||	(FLASH.FSTATR0.BIT.ERSERR == 1) ){
			ret = FLD_ERROR;
		}
	}
	//protect and disable to erase
	FLASH.FWEPROR.BIT.FLWE = 2;
	FLASH.DFLWE0.WORD = 0x1E00;
	return ret;
}

int32_t fld_program_2byte( uint32_t addr, uint16_t *ram )
{
	volatile uint8_t *addr_b = (uint8_t *)addr;
	volatile uint16_t *addr_w = (uint16_t *)addr;
	int32_t ret = FLD_OK;
	// Unprotect and enable to write all blocks
	FLASH.FWEPROR.BIT.FLWE = 1;
	FLASH.DFLWE0.WORD = 0x1EFF; // 1Eh is Key
	//FLASH.DFLWE1.WORD = 0xE1FF; // E1h is Key
	// execute the 2-byte programming command
	*addr_b = 0xE8;
	*addr_b = 0x01;
	*addr_w = *ram;
	*addr_b = 0xD0;
	// wait for tDP8 time (timeout is 2.2ms)
	if( wait_FRDY( 2*1000*1.1 ) == FLD_TMOUT ){
		reset_fcu();
	}
	// error check
	if( (FLASH.FSTATR0.BIT.ILGLERR == 1) ||	(FLASH.FSTATR0.BIT.PRGERR == 1) ){
		ret = FLD_ERROR;
	}
	//protect and disable to write
	FLASH.FWEPROR.BIT.FLWE = 2;
	FLASH.DFLWE0.WORD = 0x1E00;
	//FLASH.DFLWE1.WORD = 0xE100;
	return ret;
}

int32_t fld_program_8byte( uint32_t addr, uint16_t *ram )
{
	volatile uint8_t *addr_b = (uint8_t *)addr;
	volatile uint16_t *addr_w = (uint16_t *)addr;
	int32_t i,ret = FLD_OK;
	// Unprotect and enable to write all blocks
	FLASH.FWEPROR.BIT.FLWE = 1;
	FLASH.DFLWE0.WORD = 0x1EFF; // 1Eh is Key
	//FLASH.DFLWE1.WORD = 0xE1FF; // E1h is Key
	// execute the 8-byte programming command
	*addr_b = 0xE8;
	*addr_b = 0x04;
	for(i=0; i<4; i++){ // 8-byte is 4 word size
		*addr_w = *ram++;
	}
	*addr_b = 0xD0;
	// wait for tDP8 time (timeout is 2.2ms)
	if( wait_FRDY( 2*1000*1.1 ) == FLD_TMOUT ){
		reset_fcu();
	}
	// error check
	if( (FLASH.FSTATR0.BIT.ILGLERR == 1) ||	(FLASH.FSTATR0.BIT.PRGERR == 1) ){
		ret = FLD_ERROR;
	}
	//protect and disable to write
	FLASH.FWEPROR.BIT.FLWE = 2;
	FLASH.DFLWE0.WORD = 0x1E00;
	//FLASH.DFLWE1.WORD = 0xE100;
	return ret;
}

int32_t fld_enable_read(void)
{
	// change to read mode
	if( FLASH.FENTRYR.WORD & 0x00ff ){
		FLASH.FENTRYR.WORD = 0xAA00; // AAh is key
	}
	// enable to read all blocks
	FLASH.DFLRE0.WORD = 0x2DFF; // 2Dh is Key
	//FLASH.DFLRE1.WORD = 0xD2FF; // D2h is Key
	return FLD_OK;
}

int32_t fld_enable_PE(void)
{
	//change to PE mode
	if( (FLASH.FENTRYR.WORD & 0x00ff) != 0x0080 ){
		FLASH.FENTRYR.WORD = 0xAA80; // AAh is key
	}
	//disabled to read all blocks
	FLASH.DFLRE0.WORD = 0x2D00; // 2Dh is Key
	return FLD_OK;

}

int wait_FRDY(unsigned int wait){
	unsigned int cnt=0;
	while(FLASH.FSTATR0.BIT.FRDY==0){
		delay_us(1);
		cnt++;
		if(cnt==wait) return FLD_TMOUT;
	}
	return FLD_OK;
}

static void reset_fcu(void)
{
	volatile int32_t w;
	// FCU reset
	FLASH.FRESETR.BIT.FRESET = 1;
	// wait for tRESW2 time (tRESW2 is 35us)
	delay_us(35);
	// clear FCU reset
	FLASH.FRESETR.BIT.FRESET = 0;
}

使用例

E2データフラッシュ領域の先頭へ0xFFFFを書き込み、その後読み出す。

	// 00100000h is top address of DB00 block
	uint32_t top_addr_db00 = 0x00100000;
	volatile uint16_t *read;

	unsigned short int test =0xFFFF;
	unsigned short int *test_data=&test;

	fld_init_pclk_notification();
	// change to P/E mode
	fld_enable_PE();
	// blank check (2 KB)
	if( fld_blank_check_2KB( top_addr_db00 ) !=FLD_BLANK ){
	// block erase
	fld_erase_2KB( top_addr_db00 );
	}
	// 2byte programming
	fld_program_2byte( top_addr_db00, test_data );
	// set enable to read
	fld_enable_read();
	read = (uint16_t *)top_addr_db00;

 

自作CPU #16 RIIC設定

ブートローダであるRX220にアドレスバスとかクロックとかリセットとか一部のレジスタ等をつなげまくったのでほとんどのピンを使った。しかしRAMへのデータ線はRXには繋がっていない。64ピンを使ったがピン数が足らないのでIOエクスパンダを使った。 MCP23017というやつこのIOエクスパンダはI2Cで通信する仕様でこのためにRX220のRIICという機能を使った。送信はスムーズに行えた。

IOエクスパンダに出力Hを設定したときの波形

f:id:Hamakita:20180130150239j:plain

しかしながら受信で手間取った。受信関数については公式のサンプルプログラムを参考に作りました。だけど少し手直しが必要でRIIC0.ICMR3.BIT.ACKBT=1を書く前にRIIC0.ICMR3.BIT.ACKWP=1を実行する必要があったみたいです。これに気付くのにずいぶん時間が掛かってしまった。

追記 どうやら公式資料ではRIICの初期化でRIIC0.ICMR3.BIT.ACKWP=1を実行していたみたいです。

サンプルプログラム

https://elearning.renesas.com/pluginfile.php/355/mod_folder/content/0/RX_MCU_Japanese/RX63N_RIIC.pdf

RIIC初期化関数

void RIICinit(void){
    SYSTEM.PRCR.WORD = 0xA502;	//プロテクト解除
    MSTP(RIIC0) = 0;				//RIIC起動
    SYSTEM.PRCR.WORD = 0xA500;	//プロテクト
    //IOポート設定
    MPC.PWPR.BIT.B0WI = 0;      //プロテクト解除
    MPC.PWPR.BIT.PFSWE = 1;		//プロテクト解除
    MPC.P16PFS.BIT.PSEL = 0x0F; //P16/SCL
    MPC.P17PFS.BIT.PSEL = 0x0F; //P17/SDA
    MPC.PWPR.BIT.PFSWE = 0;     //プロテクト
    MPC.PWPR.BIT.B0WI = 1;		//プロテクト
    PORT1.PMR.BIT.B6 = 1;       //P16/周辺
    PORT1.PMR.BIT.B7 = 1;       //P17/周辺

    do{    RIIC0.ICCR1.BIT.ICE=0;
    }while(RIIC0.ICCR1.BIT.ICE!=0);
    RIIC0.ICCR1.BIT.IICRST=1;
    RIIC0.ICCR1.BIT.ICE=1;
    RIIC0.ICSER.BYTE =0x00;
    RIIC0.ICMR1.BIT.CKS=0x03;//PCLK/8で動作
    RIIC0.ICBRH.BIT.BRH=0x02;//通信速度の設定
    RIIC0.ICBRL.BIT.BRL=0x03;
    //RIIC0.ICMR2.BYTE = 0x00;//保留
    //RIIC0.ICMR3.BYTE = 0x00;
    //RIIC0.ICFER.BYTE = 0x00;
    RIIC0.ICFER.BYTE = 0x00;//割り込み設定
    RIIC0.ICCR1.BIT.IICRST=0;//内部リセット解除
}

マスター受信関数

int MasterRead(_UBYTE Sad,int clen,_UBYTE *cdata,int rlen,_UBYTE *rdata){
	int RE=-1;
	int ccnt=0;
	int rcnt=0;
	_UBYTE send;
	volatile _UBYTE dummy;
	while(RIIC0.ICCR2.BIT.BBSY!=0);
	RIIC0.ICCR2.BIT.ST=1;
	if(0<clen){
		while(RIIC0.ICSR2.BIT.NACKF==0){
			if(RIIC0.ICSR2.BIT.TDRE==0){
				continue;
			}
			if(ccnt==0){
				send=Sad&0xFE;
			}
			else{
				send=cdata[ccnt-1];
			}
			RIIC0.ICDRT=send;
			if(ccnt==clen){
				while(RIIC0.ICSR2.BIT.TEND!=1);
				RE=0;
				break;
			}
			ccnt++;
		}
		RIIC0.ICCR2.BIT.RS=1;
		while(RIIC0.ICCR2.BIT.RS!=0);
	}
	while(RIIC0.ICSR2.BIT.TDRE!=1);
	RIIC0.ICDRT=Sad|0x01;
	while(RIIC0.ICSR2.BIT.RDRF!=1);
	///
	if(RIIC0.ICSR2.BIT.NACKF==0){//0ならスレーブが認識されている
		if(rlen == 1){
			RIIC0.ICMR3.BIT.ACKWP=1;//ACKBTへのプロテクト解除
			RIIC0.ICMR3.BIT.ACKBT=1;//NACKを送信する
		}
		else if(rlen==2){
			RIIC0.ICMR3.BIT.WAIT=1;
		}
		dummy = RIIC0.ICDRR;
		while(rcnt<rlen-1){
			while(RIIC0.ICSR2.BIT.RDRF!=1);
			if(rcnt+1==rlen-2){
				RIIC0.ICMR3.BIT.WAIT=1;
			}
			else if(rcnt+1==rlen-1){
				RIIC0.ICMR3.BIT.ACKWP=1;//ACKBTへのプロテクト解除
				RIIC0.ICMR3.BIT.ACKBT=1;//NACKを送信する
			}
			rdata[rcnt]=RIIC0.ICDRR;
			rcnt++;
		}
		while(RIIC0.ICSR2.BIT.RDRF!=1);
		RIIC0.ICSR2.BIT.STOP=0;
		RIIC0.ICCR2.BIT.SP=1;
		rdata[rcnt]=RIIC0.ICDRR;
		RIIC0.ICMR3.BIT.WAIT=0;
	}
	else{
		RE=-1;
		RIIC0.ICSR2.BIT.STOP=0;
		RIIC0.ICCR2.BIT.SP=1;
		dummy=RIIC0.ICDRR;
	}
	while(RIIC0.ICSR2.BIT.STOP!=1);
	RIIC0.ICSR2.BIT.NACKF=0;
	RIIC0.ICSR2.BIT.STOP=0;
	return RE;

}

自作CPU #15 外部端子割り込みと周辺機能って同時に使用できるんですね

f:id:Hamakita:20180117111830j:plain

開発中の4ビットCPUの名前を発表します。

TTM4

と名付けました。実はずっと前からこの名前をつけていました、この名前はとりあえずの仮名としてつけていて後からもっと良い名前をつけようと思っていたのですが結構かっこ良いし、ずっと開発中TTM4と自分の中で呼んでいたので愛着がわきました。

由来は

ちかちか祭り4bit

です。名前をつける必要性が生じたときにブレッドボードでチカチカしていたLEDが目に留まってこの名前になりました。あくまで仮名のつもりだったので

開発の参考にさせていただいた"CPUの創り方"で紹介されているTD4と名前が似ちゃってます。

さてこのTTM4にはブートローダが載っています。パソコンで言うところのBIOSで、プログラムをROMからRAMへ読み込むのが主な役目です。

ブートローダにはRX220というマイコンを採用しました。ブートローダの方が圧倒的に高性能だというツッコミはなしで。秋月電子で売ってます。

RX220マイコン R5F52206BDFM: マイコン関連 秋月電子通商 電子部品 ネット通販

採用した理由は

  • 5Vで動作すること
  • ピン数が多い
  • 秋月で売ってる
  • 自分がさわったことがあるので開発しやすい

RX220にはクロックジェネレータから生成したクロックやリセット、一部のレジスタ、アドレスバスなど繋いであります。パソコンとシリアル通信も可能ですので工夫すればパソコンからTTM4をコントロールできます。

今はそのためのプログラムを書いている途中です。

TTM4はLEDがたくさん付いているのでその点滅で動作の様子がわかります。しかしクロックの周波数を上げていくと点滅が早すぎて人間には動いているのか、止まっているのか判断できません。そこでRXでクロックをカウントしパソコンへカウンタを表示させるようにしました。このカウンタにはRX220の周辺機能のTMRという機能を使いました。TMRの初期化関数を下に示したいと思います。37ピンを使ってます。

void TMRinit(void){
	//TTM4CLKをカウントする
	//TMR0.TCNTで8bit,TMR1.TCNT:TMR0.TCNTで16bit
	//IOポート設定
    MPC.PWPR.BIT.B0WI = 0;      //プロテクト解除
    MPC.PWPR.BIT.PFSWE = 1;		//プロテクト解除
    MPC.PB1PFS.BIT.PSEL = 0x05; //PB1/TMCI0
    MPC.PWPR.BIT.PFSWE = 0;     //プロテクト
    MPC.PWPR.BIT.B0WI = 1;		//プロテクト
    PORTB.PDR.BIT.B1 = 0;		//入力
    PORTB.PMR.BIT.B1 = 1;       //PB1/周辺

    SYSTEM.PRCR.WORD = 0xA502;  //プロテクト解除
    MSTP(TMR0) = 0;             //モジュールストップ解除
    MSTP(TMR1) = 0;             //モジュールストップ解除
    SYSTEM.PRCR.WORD = 0xA500;  //プロテクト

    IPR(TMR1, OVI1) = 1;                    //割り込み優先度設定
    IEN(TMR1, OVI1) = 1;                    //割り込み有効
    TMR0.TCORA = 0xFF;
    TMR0.TCR.BYTE= 0x00;
    TMR1.TCR.BYTE= 0x20;//オーバーフロー割り込み有効
    TMR0.TCSR.BYTE= 0x00;
    TMR1.TCSR.BYTE= 0x00;
    TMR0.TCNT = 0;
    TMR1.TCNT = 0;
    TMR0.TCCR.BYTE= 0x01;
    TMR1.TCCR.BYTE= 0x18;//コンペアマッチでカウントで16ビットカウンタとして使う
}

これでカウンタはできたのですが、RXをクロックの立ち上がりに動作させる必要性が出てきました。外部端子状態変化割り込みで立ち上がりを検出するのが良いと思ったのですが37ピンはすでに周辺機能に割り当てられているのでTMRと同時に使用はできないと思ってました、端子に周辺機能を割り当てるレジスタには外部端子割り込みと周辺機能割り当てが別で設定できるようになっていたのを見て、ためしに同時に設定したら使えました。

外部端子割り込み初期化同じく37ピン

	//外部端子割り込み設定//CLK立ち上がり割り込み
    ICU.IER[0x08].BIT.IEN4=0;//割り込み要求禁止
    ICU.IRQFLTE0.BIT.FLTEN4=1;//デジタルフィルタ無効
    ICU.IRQFLTC0.BIT.FCLKSEL4=0x01;//デジタルフィルタサンプリング周波数
    MPC.PWPR.BIT.B0WI = 0;      //プロテクト解除
    MPC.PWPR.BIT.PFSWE = 1;		//プロテクト解除
    //MPC.PB1PFS.BIT.PSEL = 0x05; //PB1/TMCI0
    MPC.PB1PFS.BIT.ISEL =1;		//割り込み端子として使用
    MPC.PWPR.BIT.PFSWE = 0;     //プロテクト
    MPC.PWPR.BIT.B0WI = 1;		//プロテクト
    PORTB.PDR.BIT.B1 = 0;		//入力
    //PORTB.PMR.BIT.B1 = 0;       //PB1/GPIO
    //PORTB.PMR.BIT.B1 = 1;       //PB1/周辺
    ICU.IRQCR[4].BIT.IRQMD=0x02;//割り込み要因設定
    ICU.IR[68].BIT.IR=0;	//割り込みフラグを初期化
    ICU.IRQFLTE0.BIT.FLTEN4=1;//デジタルフィルタ有効
    ICU.IPR[68].BIT.IPR=1;	//割り込み優先度設定
    ICU.IER[0x08].BIT.IEN4=1;//割り込み要求有効

外部端子割り込みと周辺機能が同時に使用できるとは自分はいままで知りませんでした。他のマイコンもそうなんですかね?自分が無知なだけですか?

自作CPU #14 スタックが動いた!


前回の記事でかいた通り、自作CPUでスタックへPUSH命令が実行できませんでした。

そこでロジックアナライザーを使って解析したら原因が判明しました。

波形

f:id:Hamakita:20180117143712j:plain

CLK:クロック

SPC:SPへのクロック

WE:スタックを構成するRAMへの書き込みパルス

SP-D/U:SPのカウント方向を制御

AD0:PCの最下位ビット

00番地にpush命令、01番地に00番地へジャンプという命令を書き込みクロック1MHzでテストしてみました。AD0はプログラムカウンタの最下位ビットです。クロックの立ち上がりでアドレスが切り替わりメモリから読み出し、制御バスの値が切り替わるのですが、そのうちの一つで今回の命令で関係あるのがsp-D/Uです。これはスタックポインタのカウント方向を制御するビットで0の時カウントアップ、1の時カウントダウンとなります。

PUSH命令はカウントダウンする必要があるので00番地の命令が読み出されると1になるはずです。

普通クロックの立ち上がりで命令をロードした後、次のクロックの立ち上がりの時に実行完了するのですが、つまり00番地がカウント命令なら次の01番地の命令をリードするクロックの立ち上がりでカウントする。しかしPUSH命令のときは少し特殊でスタックポインタは常にデータが入っている先頭をさしますので次のクロックの立ち上がりまでに

SPの値を-1

スタックを構成するRAMへデータ書き込み

を行う必要がありました。そこで

命令が読み出されるクロックの立ち上がりをトリガーにしてマルチバイブレータでパルスを生成、その後クロックの立下りをトリガーにしてRAMへの書き込みパルスを生成

という仕組みをつくりました。

しかしサンプリングされた波形をみてみると

00番地の命令をロードした後、SPCにマルチバイブレータにより 生成されるべきクロックが確認できません。これの原因は明白でSP-D/Uのロードに時間がかかっているせいです。SPCはマルチプレクサを通して、クロックとマルチバイブレータとで切り替えています。この切り替えもSP-D/Uが行っているので、ロードに時間がかかるとSPCにパルスが出てこなかったのだろうと思います。

そこでクロックの立ち上がりをトリガーにするのではなくSP-D/Uをトリガーにするように変更してみました。SP-D/Uが立ち上がるのはPUSH命令の時だけで他の命令では常に0ですので期待通りの動作が実現できると思います。

パターンを切ってつなぎ変えました。

 

f:id:Hamakita:20180118013625j:plain

修正後動作確認しましたら無事PUSH命令を実行できました。

修正後の波形 SPCに短いパルスが確認できる

f:id:Hamakita:20180118013158j:plain

スタックは今回のCPU作りで最も気合をいれて設計したうちの一つなので無事動かせて一安心です。

自作CPU #13 PUSHがうまくできない



自作CPUにはスタックを構成して載せました。しかし動作確認をしているとスタックへデータを積み上げるPUSH操作がうまくできないことが分かりました。ブレッドボード上で実験していた時はできていたのに…普通こういう回路を組む時、スタックの操作は数クロック使ってやると思います。しかし私のは、CPUの創り方のTD4を大元にしていますので、すべての命令が1クロックで実行されます。PUSH、POPも例外でなく、1クロックで実行できるようにしています。PUSHはスタックポインタを先にデクリメントしてデータを格納、POPはデータを取り出してからインクリメントしないといけないので、(スタックポインタを操作する順番が違う)マルチプレクサやらマルチバイブレータをつかってなんとか1クロックで実行できるようにしました。

実験中

 

f:id:Hamakita:20180117111830j:plain

弄っているうちにどうやら手でマシン語を操作する分には期待通りの動作をしていることが分かりました。プログラムを書き込んで実行させるとダメみたいです。