.global start
PS = 0177776
.text
.even
start:
mov $0010000, sp / set kernel mode's stack pointer
mov $0140000, PS / change current mode to user mode
mov $0020000, sp / set user mode's stack pointer
mov 0, r0
/ copy vector table to zero address
mov $vector, r1
mov $vectorend, r2
1$: mov (r1)+,(r0)+
cmp r1,r2
bne 1$
trap 0377
2$: br 2$
trap:
mfpi sp / push in stack previous mode's stack pointer
rti
.data
.even
vector:
.word 0
.word 0
/ trap vectors
.word 0, 0 / bus error
.word 0, 0 / illegal instruction
.word 0, 0 / bpt-trace trap
.word 0, 0 / iot trap
.word 0, 0 / power fail
.word 0, 0 / emulator trap
.word trap, 0346 / system entry
vectorend = .
.end
sim> e -m 1000:1100
1000: MOV #10000,SP
1004: MOV #140000,177776
1012: MOV #20000,SP
1016: MOV 0,R0
1022: MOV #1050,R1
1026: MOV #1110,R2
1032: MOV (R1)+,(R0)+
1034: CMP R1,R2
1036: BNE 1032
1040: TRAP 377
1042: BR 1042
1044: MFPI SP
1046: RTI
1050: HALT
1052: HALT
1054: HALT
1056: HALT
1060: HALT
1062: HALT
1064: HALT
1066: HALT
1070: HALT
1072: HALT
1074: HALT
1076: HALT
1100: HALT
sim> br 1044
sim> g
Breakpoint, PC: 001044 (MFPI SP)
sim> e psw
PSW: 030346
sim>
.word trap, 0346 / system entry
sim> e sp
SP: 007774
sim> e 7770:10000
7770: 000000
7772: 000000
7774: 001042
7776: 140004
10000: 000000
sim> s
Step expired, PC: 001046 (RTI)
sim> e 7770:10000
7770: 000000
7772: 020000
7774: 001042
7776: 140004
10000: 000000
"ld.scr" ENTRY(start) SECTIONS { . = 24*2048-512; .text : { *(.text) *(.rodata) } .data : { *(.data) } .bss : { *(.bss) } end = .; }
"start.S" .GLOBAL _cstart STACK = 24*2048-514 .text .even .globl start start: mov $STACK, sp jsr pc, _cstart mov $start,-(sp) clr pc .end
"inod.h" typedef unsigned int uint16_t; typedef int int16_t; struct inode { uint16_t i_mode; char i_nlink; char i_uid; char i_gid; char i_size0; uint16_t i_size1; uint16_t i_addr[8]; int16_t i_atime[2]; int16_t i_mtime[2]; }; typedef struct inode inode_t; /* modes */ #define IALLOC 0100000 #define IFMT 060000 #define IFDIR 040000 #define IFCHR 020000 #define IFBLK 060000 #define ILARG 010000 #define ISUID 04000 #define ISGID 02000 #define ISVTX 01000 #define IREAD 0400 #define IWRITE 0200 #define IEXEC 0100
"main.c" #include "ino.h" #define RK11_CTL_REG_ADDR (0177400) #define CODE_ADDR (((unsigned int)24*2048)-512) #define INODE_BUF_ADDR (CODE_ADDR-1024) #define RKRDY (1<<7) struct dir_info { uint16_t ino; char name[14]; }; struct rk11 { uint16_t rkds; // 0177400 uint16_t rker; // 0177402 uint16_t rkcs; // 0177404 uint16_t rkwc; // 0177406 uint16_t rkba; // 0177410 uint16_t rkda; // 0177412 }; static volatile struct rk11 *rk11_p = (struct rk11*)RK11_CTL_REG_ADDR; static volatile inode_t *inod = (inode_t*)INODE_BUF_ADDR; static volatile int *buf = (int*)INODE_BUF_ADDR+sizeof(inode_t); /*---------------------------------- -----------------------------------*/ void memcpy(volatile void *dst, volatile void *src, int n) { while(n--) *(char*)dst++ = *(char*)src++; } int streq(char *src, char *dst) { while(*src != 0 && *dst != 0) if(*src++ != *dst++) return 0; return 1; } void read_blk(volatile void *buf, int blk_no) { unsigned int cylnd = (blk_no/12)>>1; unsigned int plane = (blk_no/12)&1; unsigned int sect = (blk_no%12); rk11_p->rkda = (cylnd<<5)|(plane<<4)|sect; rk11_p->rkba = (uint16_t)buf; rk11_p->rkwc = -256; rk11_p->rkcs = 5; // READ & GO while(!(rk11_p->rkcs & RKRDY)) ; } void iget(int ino) { int blk_no = (31+ino)/16; int i_offset = 32*((31+ino)%16); read_blk(buf, blk_no); memcpy(inod, buf+i_offset, 32); } int cstart() { static volatile void *zero_adr = 0; struct dir_info *dir_p; int i; // get root's inode info iget(1); read_blk(buf, inod->i_addr[0]); // get kernel inode info dir_p = (struct dir_info*)buf; for(i = 0; i < 512/16 && dir_p->name[0] != 0; i++, dir_p++) { if(streq(dir_p->name, "unix")) { iget(dir_p->ino); break; } } // read kernel binary file to address zero read_blk(buf, inod->i_addr[0]); for(i = 0; i < 256 && buf[i]!=0; i++) { read_blk(zero_adr+i*512, buf[i]); } if( *(int*)zero_adr == 0407) { memcpy(zero_adr, zero_adr+020, inod->i_size1); } return 0; }
t_rdsk $cat start.S
.GLOBAL start
.GLOBAL _cstart
STACK = 0x1000
.text
start:
mov $STACK, sp
jsr pc, _cstart
halt
.end
#define RK11_CTL_REG_ADDR (0177400) static volatile struct rk11 { uint16_t rkds; // 0177400 uint16_t rker; // 0177402 uint16_t rkcs; // 0177404 uint16_t rkwc; // 0177406 uint16_t rkba; // 0177410 uint16_t rkda; // 0177412 } *rk11_p = (struct rk11*)RK11_CTL_REG_ADDR; void read_blk(void *buf, int blk_no) { unsigned int cylnd = (blk_no/12)>>1; unsigned int plane = (blk_no/12)&1; unsigned int sect = (blk_no%12); rk11_p->rkda = (cylnd<<5)|(plane<<4)|sect; rk11_p->rkba = (uint16_t)buf; rk11_p->rkwc = -256; rk11_p->rkcs = 5; // READ & GO while(!(rk11_p->rkcs & RKRDY)) ; }
Hex Oct name
------------------------------------------------
0xFF00 0177400 RKDS ドライブの状態を表す
0xFF02 0177402 RKER エラーの状態を表す
0xFF04 0177404 RKCS ディスク制御に使用される
0xFF06 0177406 RKWC 転送データサイズを表す
0xFF08 0177410 RKBA メモリ中の転送データのアドレス
0xFF0A 0177412 RKDA ドライブ中の転送データのアドレス
------------------------------------------------
#!/usr/bin/ruby
(ARGV[0] && ARGV[1]) || abort("usage: ruby bin2load.rb <a.out> <outfile>")
class LdaFile < File
def write_dat(data)
cksum = 0
data.each do |d|
write [d].pack("C")
cksum += d
end
return cksum
end
def write_sec(saddr, data)
return if data == nil || data.size <= 0
write_sec_h saddr, data
end
def write_sec_h(saddr, data=[])
cksum = write_dat [1,0]
cksum += write_dat [data.size+6].pack("v").unpack("C*")
cksum += write_dat [saddr].pack("v").unpack("C*")
cksum += write_dat data if data.size > 0
cksum = -(cksum & 0xff)
write [cksum].pack("C")
end
end
fin = File.open(ARGV[0],"r")
fout = LdaFile.open(ARGV[1], "w")
magic, text_sz, data_sz, bss_sz, syms_sz, entry_adr, unused, flag =
fin.read(2*8).unpack("S*")
fout.write_sec entry_adr, fin.read(text_sz).unpack("C*")
fout.write_sec entry_adr+text_sz, fin.read(data_sz).unpack("C*")
fout.write_sec entry_adr+text_sz+data_sz, Array.new(bss_sz, 0)
fout.write_sec_h entry_adr
fin.close
fout.close
static const uint16 boot_rom[] = { 0042113, /* "KD" */ 0012706, BOOT_START, /* MOV #boot_start, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ 0000303, /* SWAB R3 */ 0006303, /* ASL R3 */ 0006303, /* ASL R3 */ 0006303, /* ASL R3 */ 0006303, /* ASL R3 */ 0006303, /* ASL R3 */ 0012701, 0177412, /* MOV #RKDA, R1 ; csr */ 0010311, /* MOV R3, (R1) ; load da */ 0005041, /* CLR -(R1) ; clear ba */ 0012741, 0177000, /* MOV #-256.*2, -(R1) ; load wc */ 0012741, 0000005, /* MOV #READ+GO, -(R1) ; read & go */ 0005002, /* CLR R2 */ 0005003, /* CLR R3 */ 0012704, BOOT_START+020, /* MOV #START+20, R4 */ 0005005, /* CLR R5 */ 0105711, /* TSTB (R1) */ 0100376, /* BPL .-2 */ 0105011, /* CLRB (R1) */ 0005007 /* CLR PC */ };
0012741, 0177000, /* MOV #-256.*2, -(R1) ; load wc */
sim> set cpu 11/40
Disabling XQ
sim> show cpu
CPU, 11/40, NOFIS, idle disabled, autoconfiguration enabled, 256KB
メモリ256KB。フルフルに積んでるぜ^^、て感じ。
とりあえず、ネットの情報を集めて PDP-11のクロスコンパイル環境を構築してみた。
動作環境はsimhのPDP-11のエミュレーション環境。
■gccのPDP-11クロス環境 (Mac OS X 10.9.x)
以下のバージョンでビルドに成功した。
環境は基本的に、以前ARM用に作ったものをベースにしている。
http://oodiarydiary.blog.so-net.ne.jp/2014-03-16
gcc-4.8.2 のビルドにはgmp, mpfr, mpcが必要。
すでにインストール済みだったので今回は省けた。
(1) binutils-2.24
展開したディレクトリの下で
$ mkdir build
$ cd build
$ CFLAGS=-Wno-error=deprecated-declarations ../configure --target=pdp11-aout --disable-nls --prefix=/usr/local/pdp11-aout
$ make
$ sudo make install
(2) gcc-4.8.2
展開したディレクトリの下で
$ mkdir build
$ cd build
$ ../configure --target=pdp11-aout --disable-nls --disable-threads --disable-shared --disable-libssp --enable-languages=c --with-gmp=/usr/local/gmp --with-mpfr=/usr/local/mpfr --with-mpc=/usr/local/mpc --prefix=/usr/local/pdp11-aout
$ make
$ sudo make install
■PDP-11上で動かす
以下のサイトの記事をまんま参考にした。
http://ancientbits.blogspot.jp/2012/07/programming-barebones-pdp11.html
上記の記事では、PDP-11用のリンカスクリプトを作って、
最後にa.outファイルを生成するが、このままでは動かない。
ヘッダー部を削るために、この人は独自に作ったbin2loadというコマンドを作った。
今回は手順通りにこれを使ってPDP-11上でhello worldまで動かせた。
GOOD!!
次回は、テストプログラムを作りながら動きを確かめてみよかなと。