FME-7 採用基板での flash 化

flashpad-maskrom32 の評価を兼ねてやりました。わりとうまくいってるのですが、 charcter ROM の erase の動作が1度目は必ず失敗し、2度目以降が安定するのが謎。

program flash memory の配線

A18 = GND
A17:13 = program ROM A17:13 (from FME-7)
CE# = nand(1, nand(ROMSEL#, nand(CPU A14, CPU A13)))
OE# = program ROM EN# (from FME-7)
WE# = CPU R/W

CE# の decode について。 FME-7 系では CPU address $6000-$7fff を ROM にする機能がありますので、 ROMSEL# を直結するとこの機能を使用するソフトが正しく動きません。

よって $6000-$7fff を含めて ~((~ROMSEL# & A14 & A13 & PHI2) & ~ROMSEL#) という式ができました。これを最適化していくとどういうわけか NAND ゲート 3 つになり、 nand(PHI2, nand(ROMSEL#, nand(CPU A14, CPU A13))) となります。 A14, A13 は CPU address で、 FME-7 から出力される ROM address をつないではいけません。

PHI2 をつないで波形見てたら、programming できませんでしたので、PHI2 成分は抜きました。 OE# のほうに PHI2 成分や使用可能レジスタのデータが入るのでたぶんいいと思います。

このため address decode は $6000-$7fff では programming 波形を正しく送ることが出来ませんが、問題ないでしょう。

charcter flash memory の配線

A18 = GND
A17:13 = charcter ROM A17:13 (from FME-7)
CE# = PPU A13
OE# = PPU RD#
WE# = PPU WR#

こちらは普通ですが、前述のように1度目の erase がなぜか失敗します。 program flash を付ける前にこちらだけを先に試したときはこんな挙動はなかったように思えますので、 バスのデコードが悪いのかな?

script

board <- {
	mappernum = 69, vram_mirrorfind = false, ppu_ramfind = false,
	cpu_rom = {
		size_base = 1 * mega, size_max = 2 * mega,
		banksize = 0x2000
	}, cpu_ram = {
		size_base = 0x2000, size_max = 0x2000, 
		banksize = 0x2000
	}, ppu_rom = {
		size_base = 1 * mega, size_max = 2 *mega,
		banksize = 0x0400
	}
};

/*
SUNSOFT-5A, SUNSOFT-5B, FME-7
[CPU writemap]
$6000-$7fff 7:0 RAM data (if RAM is enabled)
$8000-$9fff 3:0 memory register address
$a000-$bfff 7:0 memory register data
$c000-$dfff 3:0 audio register address (SUNSOFT-5B only)
$e000-$ffff 7:0 audio register data (SUNSOFT-5B only)

[CPU readmap]
$6000-$7fff 7:0 Program ROM bank #0 or RAM
$8000-$9fff 7:0 Program ROM bank #1
$a000-$bfff 7:0 Program ROM bank #2
$c000-$dfff 7:0 Program ROM bank #3
$e000-$ffff 7:0 Program ROM bank #4 (fixed to bottom page)

[PPU readmap] (PPU write map is undefined)
0x0000-0x03ff Charcter ROM bank #0|0x1000-0x13ff Charcter ROM bank #4
0x0400-0x07ff Charcter ROM bank #1|0x1400-0x17ff Charcter ROM bank #5
0x0800-0x0bff Charcter ROM bank #2|0x1800-0x1bff Charcter ROM bank #6
0x0c00-0x0fff Charcter ROM bank #3|0x1c00-0x1fff Charcter ROM bank #7

[FME-7 memory register]
adr bit assignments
-------------------------
0-7 7:0 Charcter ROM bank #0 to #7
8   7   RAM enable bit 0:disable 1:enable
    6   memory select on $6000-$7fff 0:ROM 1:RAM
    4:0 CPU ROM page for bank #0
9-b 4:0 CPU ROM page for bank #1 to #3
c   1:0 PPU area VRAM control
d   7   φ2 counter decrement 0:disable 1:enable
    0   φ2 counter overflow IRQ 0:disable 1:enable
e   7:0 φ2 counter value bit7:0
f   7:0 φ2 counter value bit15:8

address 8, bit7:6 behave on FME-7
00 enabled ROM
01 disabled ROM and RAM
10 disabled ROM and RAM
11 enabled RAM

audio register
(not analyzed yet)

*/
function sunsoft5_write(d, register_address, data)
{
	cpu_write(d, 0x8000, register_address);
	cpu_write(d, 0xa000, data);
}

function cpu_dump(d, pagesize, banksize)
{
	local regaddress = 9
	local cpuaddress = 0x8000
/*
	//*debug* dump ROM data via $6000-$7fff
	regaddress = 8
	cpuaddress = 0x6000
*/
	for(local i = 0; i < pagesize - 1; i++){
		sunsoft5_write(d, regaddress, i);
		cpu_read(d, cpuaddress, banksize);
	}
	cpu_read(d, 0xe000, banksize);
}

function ppu_dump(d, pagesize, banksize)
{
	local mul = 8;
	for(local i = 0; i < pagesize; i+= mul){
		for(local j = 0; j < mul; j++){
			sunsoft5_write(d, j, i + j);
		}
		ppu_read(d, 0, banksize * mul);
	}
}

function cpu_ram_access(d, pagesize, banksize)
{
	sunsoft5_write(d, 8, 0xc0);
	cpu_ramrw(d, 0x6000, banksize);
	cpu_write(d, 0xa000, 0x00);
}

/*
CPU memory bank
cpu address|rom address    |page|task
$8000-$9fff|0x02000-0x03fff|1   |write 0x2aaa
$a000-$bfff|0x04000-0x05fff|2   |write 0x5555
$c000-$dfff|n * 0x2000     |n   |programming area
$e000-$ffff|0x3c000-0x3ffff|fix |program last page

PPU memory bank
ppu address  |rom address    |page|task
0x0000-0x0fff|n * 0x1000     |n   |programming area
0x1000-0x13ff|0x02800-0x02fff|0x0a|write 0x2aaa
0x1400-0x17ff|0x05000-0x057ff|0x15|write 0x5555
0x1800-0x1fff|未使用
*/
function program_initalize(d, cpu_banksize, ppu_banksize)
{
	sunsoft5_write(d, 8, 1 << 6); //disable W-RAM

	cpu_command(d, 0x2aaa, 0xa000, cpu_banksize);
	cpu_command(d, 0x5555, 0xc000, cpu_banksize);
	sunsoft5_write(d, 0xa,1);
	sunsoft5_write(d, 0xb,2);

	ppu_command(d, 0x2aaa, 0x1000, ppu_banksize);
	ppu_command(d, 0x5555, 0x1400, ppu_banksize);
	ppu_command(d, 0x0000, 0x1800, ppu_banksize);
	//なぜかよくわからないが電源投入直後の erase に失敗する (2度は必ず成功する)
/*	for(local j = 0; j < 0x80; j++){
		sunsoft5_write(d, j & 0x07, j);
	}*/
	sunsoft5_write(d, 4, 0x0a);
	sunsoft5_write(d, 5, 0x15);
	sunsoft5_write(d, 6, 0);
}

function cpu_transfer(d, start, end, cpu_banksize)
{
	for(local i = start; i < end - 1; i += 1){
		sunsoft5_write(d, 9, i);
		cpu_program(d, 0x8000, cpu_banksize);
	}
	//$6000-$7fff への不正アクセスを避けるため $e000-$ffff は使用しない
	sunsoft5_write(d, 9, 0xff & 0x1f);
	cpu_program(d, 0x8000, cpu_banksize);
}

function ppu_transfer(d, start, end, ppu_banksize)
{
	local mul = 4
	for(local i = start; i < end; i += mul){
		for(local j = 0; j < mul; j++){
			sunsoft5_write(d, j, i + j);
		}
		ppu_program(d, 0x0000, ppu_banksize * mul);
	}
}

special thanks

xsnake氏, 回路図作ってくれたのでモチベーションが下がらずにいけました。