2012年10月20日星期六

Building a Red Power Operating System Episode 1: Hello World

Hi everyone. This is a blog for recording all my personal technical stuff. This time, I'm working on the creation of a fully-featured operating system named WishOS for computers in RedPower 2 (a mod for MineCraft). I will continually write small episodes to record my progress onto this project. Once finished, this would become a hacking tutorial for everyone.

To start my work, I have done some research for redpower computers. Basically these computers have a microcontroller derived from the 6502 (the one in Commodore 64!). Although it emulates nearly a fully functional hardware, it lacks good software support. The original bundled operating system, MineOS, has only a FORTH compiler and nothing else. Despite the poor functionality of FORTH, since the system has only a compiler, the code of a program cannot be viewed or changed once it's entered into the system. It has nothing for file systems, either.

So it is obvious I need start building a temporary toolchain for bootstrapping my final system. The temporary toolchain contains only a text editor and a compiler. I will use the text editor to edit system code, and the compiler to make the bootable floppy disk. The binary always starts from the 0 sector. The code will be placed at a fixed starting sector. This design eliminates the need for file systems.

In this episode, I'm going to write a FORTH program which builds a bootable floppy disk, which just prints the legendary "Hello World!" text when being booted.

Firstly we need to understand the way redpower computer boots. The BIOS code can be found at http://integratedredstone.wikispaces.com/RedPower+Control and I will not duplicate the words. The BIOS basically reads floppy disk sectors and put them into memory address at 0x0500.

When looking at the wiki page, you may have noticed the term "emulation mode". This is a mode used by the 65C816 processor (a 16-bit processor) to behave as the 8-bit processor 6502 for providing backwards compatibility. The RedPower CPU is actually a combination of 6502, 65C02 and 65C816 with custom modifications, so it comes with the emulation mode, too. The key point here is that emulation mode makes it possible that you can switch the registers and memory accesses between 8-bit and 16-bit.

Then I just start building the code. I need a basic buffer management utility to manage compiled code buffer.

VARIABLE buf
16384 ALLOT buf !
VARIABLE pos

: CLR
buf @ pos ! ;

: WB
pos @ !
pos @ 1 + pos !
;

: WD
pos @ !
pos @ 2 + pos !
;

Then I have to write instruction emitters for every instruction I'd like to use. To avoid useless work, I wrote the hello world program in assembly at this time point to check what instructions are needed.

0500 18         CLC             ; clear carry
0501 FB         XCE             ; set native mode
0502 C2 30      REP #$30        ; use 16-bit registers

0504 A9 01 00   LDA #$1         ; default id of monitor
0507 EF 00      MMU #$0         ; set redbus
0509 A9 00 03   LDA #$300
050C EF 01      MMU #$1         ; set redbus memory mapping
050E EF 02      MMU #$2         ; enable redbus

0510 A9 01 00   LDA #$1         ; row 1
0513 8D 00 03   STA $300

0516 E2 30      SEP #$30        ; use 8-bit registers
0518 A2 00      LDX #$0         ; loop variable

loop:
051A BD 40 05   LDA $540, X     ; load current character
051D C9 00      CMP #$00        ; zero-terminated string
051F F0 07      BEQ final
0521 9D 10 03   STA $310, X     ; save current character to screen buffer
0524 E8         INX
0525 4C 1A 05   JMP loop

final:
0528 4C 28 05   JMP final       ; dead loop

0540 48 65 6C   "Hello World!", $00
     6C 6F 20
     57 6F 72
     6C 64 21
     00

Now I can define useful instruction emitters. I quickly recognized some instructions have more than one address modes (see http://www.obelisk.demon.co.uk/6502/addressing.html for explanation for each address mode), to distinguish between them, I added suffixes to instruction names.

SuffixesAddress ModeExample
No suffixesDirect absolute/relative address, or instructions having only one address modeLDA $33
IImmediate valueLDA #128
XAbsolute address + XLDA $100, X
YAbsolute address + YLDA $100, Y
IDIndirectJMP ($200)
IXIndexed indirect (X)LDA ($100, X)
IYIndirect indexed (Y)LDA ($100), Y
ZZero pageLDA $FF
ZXZero page + XLDA $FF, X
ZYZero page + YLDA $FF, Y
88 bit formSee below

The last one is a special suffix which can be appended to all above suffixes to indicate the 8-bit form of that instruction. (By default 16-bit forms of instructions are used.)

After all these preparations, it is now easy to program the instruction emitters. (Remember to run HEX to enter hexadecimal number mode.)

: CLC 18 WB ;
: XCE FB WB ;
: REP C2 WB WB ;
: SEP E2 WB WB ;
: MMU EF WB WB ;
: LDAI A9 WB WD ;
: STA 8D WB WD ;
: LDXI8 A2 WB WB ;
: LDAX BD WB WD ;
: STAX 9D WB WD ;
: CMPI8 C9 WB WB ;
: BEQ F0 WB WB ; (Relative addresses are always 8 bit)
: INX E8 WB ;
: JMP 4C WB WD ;

Lastly we define a helper function to move buffer pointer to a fixed position:

: ORG 500 - buf @ + pos ! ;

We are almost there. Let's assemble the final hello world code.

CLR

CLC
XCE
30 REP
1 LDAI
0 MMU
300 LDAI
1 MMU
2 MMU

1 LDAI
300 STA

30 SEP
0 LDXI8

540 LDAX
0 CMPI8
7 BEQ
310 STAX
INX
51A JMP

528 JMP

540 ORG
48 WB
65 WB
6C WB
6C WB
6F WB
20 WB
57 WB
6F WB
72 WB
6C WB
64 WB
21 WB
0 WB

Our program is done. Try to "burn" it into the floppy disk:

buf @ 0 DISKWS
DISKNAME" Hello"

Insert this disk to another computer and boots it, you will finally see "Hello World!" on the screen:

Enjoy our first bootable floppy!

没有评论: