SunPlusのフォトフレームで使われているMIPS SOCのuartのputcのコードは以下になります。
8008d484: ff00a530 andi a1,a1,0xff
8008d488: 01118290 lbu v0,4353(a0)
8008d48c: 00000000 nop
8008d490: 42110200 srl v0,v0,0x5
8008d494: 01004230 andi v0,v0,0x1
8008d498: fbff4010 beqz v0,0x8008d488
8008d49c: 00000000 nop
8008d4a0: 0800e003 jr ra
8008d4a4: 081185a0 sb a1,4360(a0)
ステータスが+1で送信データが+8なので8250互換ではなさそうです。SOCベンダーがIPを1から作る事はないとおもうので、何らかの一般的な仕様だと思うのですが。。。
cで書いてみてました。
void cput(unsigned char *addr, unsigned char ch)
{
int tmp;
do {
tmp = *(addr + 0x1101);
} while(!((tmp >> 5) & 1));
*(addr + 0x1108) = ch;
}
これをgcc 4.9.2で-O2でコンパイルして逆アセンブルしてみます。
00000000 <cput>:
0: 90821101 lbu v0,4353(a0)
4: 30420020 andi v0,v0,0x20
8: 14400003 bnez v0,18 <cput+0x18>
c: 30a500ff andi a1,a1,0xff
10: 08000004 j 10 <cput+0x10>
14: 00000000 nop
18: 03e00008 jr ra
1c: a0851108 sb a1,4360(a0)
無限ループになってしまってます。
おそらくCで書かれた物と思われますが、レジスタを退避してないので、なんらかの最適化はかかっていると思われます。
しかしlbuした後のnopはコンパイラーが付けたとは考えにくいです。これが無いと正常に処理されません。このSOCのuartのバグかもしれません。
おそらくマクロ化したインラインアセンブラで書かれたような気がします。とりあえずべたで書いてみます。
void cput(unsigned char *addr, unsigned char ch)
{
int tmp;
do {
asm volatile ("lbu %0,0x1101(%1)\n\tnop"
: "=r" (tmp) : "r" (addr));
} while(!((tmp >> 5) & 1));
*(addr + 0x1108) = ch;
}
逆アセンブルしてみます。
00000000 <cput>:
0: 30a500ff andi a1,a1,0xff
4: 90821101 lbu v0,4353(a0)
8: 00000000 nop
c: 30420020 andi v0,v0,0x20
10: 1040fffc beqz v0,4 <cput+0x4>
14: 00000000 nop
18: 03e00008 jr ra
1c: a0851108 sb a1,4360(a0)
微妙に違いますが、動きました。
入力も分かったのですが、なんか動きが変です。
0x1100からビットで8,8,(8,8),32,8,(8,8,8),8,(8,8,8)となっていて、なんとも不思議な仕様です。カッコ内は未使用です。