2008-09-11

[好站]用各種語言實現演算法

Gentoo : Intel® Pentium® 4 Computer Language Benchmarks Game
很有趣,OCaml 其實還蠻快的,Python/PHP/Ruby 自然慢得不得了,Scheme 竟然很慢(怪!) 但 LISP SBCL 非常快!
有兩個語言出乎意料:
Isaac
Smart Eiffel
該找時間研究一下...

2008-09-06

DOS下使用flat mode的好工具 -- Watcom C

部門的專案要在 DOS 下存取 ACPI Table。依據 ACPI Specification 3.0b,ACPI Table 首先是在 F000:0000-FFFF 段中放一段 RSDP,由 "RSD PTR " 標示 RSDP 進入點,從那找到 XSDT (32位元位址,通常在 0x7Fxx_xxxx) 後,再查到 FADT 及 DSDT 。由於 XSDT, FADT, DSDT 都在32位元位址,偷懶的我自然想找些 DOS Extender 來處理,不想自己切進保護模式。
我首先想到的是 djgpp 。一直以來 djgpp 用得十分順手,像這樣:

char x = _farpeekb(_dos_ds, 0xFFFFFFE4); 或是
movedata(_dos_ds, base, _my_ds(), (unsigned)buf, len);

可是,不知道為什麼,只要存取到 0x7F 位址,SIGSEGV 馬上就跑出來,查了 ds selector 的範圍,一切都 OK ,但程式就是動不了。
爬文爬了很久,有人用 Borland C++ 編出來的程式能動,但我不想裝 Borland C++. 靈機一動,想起 DOS4GW ,上網一找果然 Watcom C 已經釋出成為免費軟體了,改名叫 Open Watcom

照著範例寫一寫,32-bit flat mode 真的很棒,像這樣:

char *ptr = (char *)0x000FFFEA;
char x = ptr[0];

這樣就可以存取了耶,讚!因為這樣我就可以

for(i = 0; i < len; i++) buf[i] = ptr[i];

了,簡捷易懂,而且以 Watcom C 的強大最佳化能力,應該不會和 djgpp 的 movedate() 差多少。

Watcom 的編譯是另一個問題。DOS 下編譯器的開關百百種,Makefile 也是各家不同。Turbo C 和 GNU Make 很不同,Watcom 也有自己的 wmake 格式。此外,32-bit flat mode 可以選的 DOS extender 非常多種,但同樣的 ACPI 程式,用 CauseWay 一樣會 SIGSEGV,但用 DOS4GW 和 PMODE/W 卻非常 OK。幸好,Open Watcom 附上了一個 IDE, 可以幫忙設定幾個旗標,再配上 sample 目錄下的 makefile, 很快就可以做出自己想要的效果了。
Watcom 的 makefile 長這樣:

LNKOPT = option quiet system pmodew
exes = oemid.exe pmbase.exe
all : $(exes) .SYMBOLIC
@%null
oemid.exe : oemid.obj
wlink $(LNKOPT) name oemid file oemid
.c.obj :
$(CC) $^& $(CFLAGS)

天啊! 什麼鬼... 還好有 sample 可以參考。把 LNKOPT 的 pmodew 換成 dos4g, 就可以做成用 DOS4GW 的執行檔了。

選用哪個 extender 也得比較比較。djgpp 預設使用 CSDPMI,沒事帶著幾個 DPMI run-time 挺煩人的。DOS4GW 一叢大大 200 多 K, 一樣讓人心情不佳。DOS/32A 很棒,但 PMODE/W 更棒更小,整個程式做完只要 30K ,不需外掛 run-time. 使用 extender 省下的切進切出保護模式的時間,也實在是讓人夠開心了。

最後講一些 djgpp 和 Watcom 的差異。這困擾了我幾個小時...
makefile 不同是小事,反正我都寫些小工具,大不了寫批次檔。差異都是些討厭的地方,像..

djgpp:

asm { "cli" }
outportl(0xcf8, i & ~3);
x = inportl(0xcfc);
asm { "sti" }

movedata(_dos_ds, RSDP+24, _my_ds(), XSDT, 4); /* 32位元位置 = 4 bytes */

Watcom:

__asm { "cli" }
outpd(0xcf8, i & ~3);
x = inpd(0xcfc);
__asm { "sti" }

#define PTRPTR(x) (char *) *(char **)(x)
XSDT = PTRPTR(RSDP+24); /* 存取指標的指標 */

這點比較起來,Watcom 的似乎比較 ANSI 一點呢! 可是啊,我真是太~~愛 djgpp 的 AT&T 式組語了。真好用。這下要切回 MASM 相容模式,還需要一點點適應的時間...