[ TOP | Recently ]

1999-07-09 bus_space


結局 stride は使わずに、全てのタイプの I/O で bus_space_tag_t を変えた。
(遅いし、stride だけだと全部をカバーできないし)

というわけで、試しに readidrom() を bus_space_read_1() を使って書いて、
NWS3400 と NWS5000 とで共有できるようにしてみた。幸せだ。

結局 5 つの bus-space を作った。

struct peripheral_8_8 {
	volatile unsigned char data;		/* data */
};

普通の 8bit mapped I/O。
news3400 の I/O はあらかたこのタイプ(? ...と思う)。

struct peripheral_4_8 {
	volatile unsigned char dummy0:4,	/* pad */
			      data_hi:4;	/* data */
	volatile unsigned char dummy1:4,	/* pad */
			      data_lo:4;	/* data */
};

NEWS3400 の IDROM がこの形式。

struct peripheral_4_32 {
	volatile unsigned char dummy0[3];	/* pad */
	volatile unsigned char dummy1:4,	/* pad */
			      data_hi:4;	/* data */
	volatile unsigned char dummy2[3];	/* pad */
	volatile unsigned char dummy3:4,	/* pad */
			      data_lo:4;	/* data */
};

同じく NEWS5000 の IDROM。

struct peripheral_8_32 {
	volatile unsigned char dummy[3];	/* pad */
	volatile unsigned char data;		/* data */
};

NEWS5000(APBUS) の 8bit I/O port はほぼこの mapping。

struct peripheral_16_64 {
	volatile unsigned int dummy0;		/* pad */
	volatile unsigned short dummy1; 	/* pad */
	volatile unsigned short data;		/* data */
};

同じく APBus の 16bit I/O。SONIC の register はこの形式で map されてる。



で、

struct newsmips_bus_space newsmips_4bit_8bit_bus_space {
	NULL,
	newsmips_bus_space_map,
	newsmips_bus_space_unmap,
	newsmips_bus_space_subregion,
	newsmips_bus_space_alloc,
	newsmips_bus_space_free,
	newsmips_bus_space_barrier,
	newsmips_4bit_8bit_rs_1,
	newsmips_4bit_8bit_rs_2,
	newsmips_4bit_8bit_rs_4,
		:
		:
};

のようにして bus_space_tag を作って、
あとはそれぞれの構造体用に bus_space 関数群を作る。結構な作業量だ。

せっかく調べたので忘れないうちにまとめておこう。

bus_space_map( bus_space_tag_t space, bus_addr_t address,
               bus_size_t size, int flags,
               bus_space_handle_t *handlep)

address から size 分の領域を、space 型のバスとして map し、そのハンドルを *handlep に格納する。以後、この領域へのアクセスは space と handle を介して行う。

が、newsmips では、全ての I/O がリニアに mapping されてるので、実際は map もなにもしていない。
ただ address をそのまま handle に入れているだけ。size にも意味はない。

bus_space_unmap(bus_space_tag_t space,
                bus_space_handle_t handle,
                bus_size_t size)

map した領域を unmap する。
当然 newsmips ではなにもしてない。

bus_space_alloc/free との違いはよくわからず。
unimplement な arch が多いけど...。

bus_space_read_{1,2,4,8}(bus_space_tag_t space,
                         bus_space_handle_t handle,
                         bus_size_t offset)

space 型の bus で、handle で示される I/O 領域の、offset の位置から
{1,2,4,8}byte 読む。
それぞれ、unsigned char, unsigned short, unsigned int, unsigned long long を返す。

newsmips の場合、space はそれぞれの method関数の table なので、
macro で (*space->read_1)(space,handle,offset) みたいなことをして関数を呼びなおしている。
この機構により bus-space によって read/write などの method が切り換えられる仕組み。

それぞれの型に対してアクセス方法を規定しているという点ではオブジェクト思考に近い。
というか bus_space 関数群の仕組みってまさにそうなんだけど。


あと、bus_space_*_8 は他のアーキテクチャでは実装されてないことが多い。

64bit I/O なんてふつー無いからいいのか?
他の arch が実装されてないことに後から気づいたのと、
ヒヨって構造体定義して C で(他の arch は高速化のため asm になってたりする)
ヘラヘラ書いちゃってたこともあって、
勢いで全部 ( bus_space_*_{1,2,4,8}) 作っちゃったよ :-(
ダマサレ。

bus_space_read_multi_{1,2,4,8}(bus_space_tag_t space,
                               bus_space_handle_t handle,
                               bus_size_t offset,
                               u_int{8,16,32,64}_t *datap,
                               bus_size_t count)

bus_space_read_? とほぼ同じだが、同じ port を count回読んで、
読めたデータを datap に count 分書きだしていく。data port を連続して読んだりする場合に使う。

bus_space_read_region_{1,2,4,8}(bus_space_tag_t space,
                                bus_space_handle_t handle,
                                bus_size_t offset,
                                u_int{8,16,32,64}_t *datap,
                                bus_size_t count)

bus_space_read_multi_? とほぼ同じだが、I/O port address も increment しながら読む。

bus_space_write_*()

bus_space_write_* は、read の同名のそれと同じ。
data の分、引数がちょっと変わる程度。

bus_space_set_region_{1,2,4,8}(bus_space_tag_t space,
                               bus_space_handle_t handle,
                               bus_size_t offset,
                               u_int{8,16,32,64}_t value,
                               bus_size_t count)

space 型の bus で、handle で示される I/O 領域の、offset byte の位置から、count 分、
value で埋める。
memset のようなもの。


bus_space_set_multiple_{1,2,4,8}(bus_space_tag_t space,
                                 bus_space_handle_t handle,
                                 bus_size_t offset,
                                 u_int{8,16,32,64}_t value,
                                 bus_size_t count)

最初 bus_space(9) にも書いてないので何すればいいんだろう、とか思ったけど、
memset が I/O port を increment するのに対し、これは同じ port に value を
count 回書き込むもののようだ。


bus_space_copy_region_1(bus_space_tag_t space,
                        bus_space_handle_t srchandle,
                        bus_size_t srcoffset,
                        bus_space_handle_t dsthandle,
                        bus_size_t dstoffset,
                        bus_size_t count)

I/O から I/O への領域 copy。
ほとんど使うことはないんじゃなかろうか...。


...とくれば、bus_space_copy_multiple_? もありそうだけど、無いようだ :P


終わり。

次回はたぶん apbus 用の intr_establish か、
Ether の attach。MAC address くらいは読みたいなぁ :-)


EOF