C--: Difference between revisions
Jump to navigation
Jump to search
[unchecked revision] | [unchecked revision] |
m C MinusMinus moved to C-- |
|||
(No difference)
|
Revision as of 22:48, 5 July 2009
C--
This page is about Sphinx Full C--, not about C--, the portable assembly language.
Sphinx Full C-- language is in between the C language and x86-assembly. It is a very neat computer language and the Shinx Full C-- compiler allows to produce (and mix) 16 bit and 32 bit code for real and protected modes.
Pros
- good for writing real mode x86 operating systems;
- good for writing TSR programs for DOS
- good for writing x86-related parts of an operating system in a structured and easily readable and easier debuggable way related to structured languages like C and Pascal;
- very good (because of the structured form) for writing small toy programs which are close to the hardware;
- very good for writing bootsectors in;
- the code can be either low level (assembly-like), medium level (C like) or very easily mixed;
- has almost as good control over all the small details of the output binaries as assembly languages provide, but is much more maintainable thanks to structuring; people develop who develop OSes in pure assembly do not need the high-level structures and portability of C and C++, so this means that for many developers, the lack of these high level structures and portability in C-- may not be an issue;
- relatively easy to port from and to C-with-assembly.
Cons
- not portable; it is very closely tied to the x86 assembly;
- is developed by few developers, the community is small; has less users than gcc so more may have more bugs;
- one compiler implementation availlable and only for one platform (DOS);
- larger projects generally should be written in high-level languages, not low-level like Sphinx Full C--;
- can be mixed with other languages in the project, where C-- is used for x86-related low level parts of the system, but doesn't give as much control as assembly and increases the number of compilers necessary;
- in order to be low-level, many limitations are in place: for example, array subscripts (like in x= myArr[subscript]) are limited to simple expressions (like myArr[10], myArr[ESI]; but myArr[myArr[1]] is not allowed);
- C code with inline assembly is no less powerful and easy to write than C--.
I am not sure on the output formats of the compiler but I fear it provides only flat-binary and dos exes. I don't know if it can output 64bit code.
Early versions of panaLiX used Sphinx Full C--.
Examples
byte x = 0b01001; word y; dword z; #define THIS_A_DEFINITION 123
Take over interrupt
dword old0x21 = {}; interrupt int0x21() { $PUSH DS $PUSH ES $PUSHA $PUSH FS // DS = CS; FS = 0xb800; FSBYTE[1682] = '!'; // $POP FS $POPA $POP ES $POP DS } ... int registerInterrupt0x21() { FS = 0; old0x21 = FSDWORD[0x21 * 4]; FSWORD[0x21 * 4] = #int0x21; FSWORD[0x21 * 4 + 2] = CS; Log(3, "0x21 registered", 0); }
ESBYTE[0x1b8003]= 'z'; // $ CLI kb_cmd(0xad); kb_cmd(0xd0); kb_read(); tepx=AL; kb_cmd(0xd1); $ MOV AL, tepx $ OR AL, 2 $ MOV tepx, AL kb_write(tepx); kb_cmd(0xae); $ STI // ESBYTE[0x1b8005]= 127;
read, write
void PRINTF() { BX = 0x0007; $ PUSH SI SI = AX; AH = 0xE; UP: $ LODSB $ CMP AL,0 $ JZ DOWN $ INT 0x10 $ JMP SHORT UP DOWN: $ POP SI } void readStr() int tr; byte b1; word ln; { tr = 0; ln = 0; do { tr = 0; b1 = wait_key(); if (b1 == 13) tr = 1; if (scanCd == 14) { tr = 2; if (ln > 0) { putch(b1); putch(' '); putch(b1); ln--; } } if (tr == 0) if (ln < 255) if (b1 >= 32) { putch(b1); BX = ln; st1[BX] = b1; ln++; }; } while (tr <> 1); BX = ln; st1[BX] = 0; }
: void kbrSpeed(byte sped, dly) { AH = 3; AL = 5; BL = sped; // 0x00 - 0x1f BH = dly; // 0 - 3 $ INT 0x16 }
Disk IO
byte readDisk(byte drive, head, sector, track, howmany; word segm, offs) int err; { err = 0; lab1: $ MOV AH, 0 $ MOV DL, drive $ INT 0x13 $ MOV AX, segm $ MOV ES, AX $ MOV BX, offs $ MOV DL, drive $ MOV DH, head $ MOV CL, sector $ MOV CH, track $ MOV AL, howmany $ MOV AH, 2 $ INT 0x13 AL = 0; if (CARRYFLAG) { err++; if (err < maxDiskErrors) $jmp lab1; return(AH); } return(0); } byte readSector(byte drive; word sector; byte howmany;word segm, offs) word a, b, c, d; { a = sector - 1; c = a % 36; d = c % 18; c = c - d; c = c / 18; b = a % 18 + 1; d = a % 36; a = a - d; a = a / 36; AL = readDisk(drive, c, b, a, howmany, segm,offs); } byte readCluster(byte drive; word clnum; byte howmany; word segm, offs) { AL = readSector(drive, clnum+32, howmany, segm, offs); } int fileCluster(word tstart) byte fbuf[512]; byte fname[11]; int n1, n2, n3, n4, w5; byte b1; byte f[11]; { $ PUSH AX $ PUSH BX $ PUSH CX $ PUSH SI lastSize = 0; w5 = 0; SI = tstart; n1 = 11; loop (n1) { $ LODSB CX = #fname +11 - n1; BX = CX; DSBYTE[BX] = AL; } $ POP SI n3 = -1; n1 = 20; do { n2 = 0; if (w5 == 0) w5 = - readSector(0, n1, 1, DS, #fbuf); if (w5 <> 0) n1 = 35; if (w5 == 0) do { n3 = 0; n4 = 0; do { AX = 32 * n2 + #fbuf + n3; BX = AX; b1 = DSBYTE[BX]; AX = #fname + n3; BX = AX; if (DSBYTE[BX] <> b1) n4 = 1; n3++; } while (n3 <= 10); AX = n2 * 32 + #fbuf + 28; BX = AX; if (n4 == 0) lastSize = DSDWORD[BX]; AX = n2 * 32 + #fbuf + 26; BX = AX; if (n4 == 0) w5=DSWORD[BX]; n2++; } while (n2 <=15); n1++; } while (n1 <= 33); $ POP CX $ POP BX $ POP AX AX = w5; }
Enable Protected Mode
... ?code32 false ... DSWORD[#gdtr] = #gdt_end - #gdt0; DSWORD[#gdtr] = DSWORD[#gdtr] - 1; DSDWORD[#gdtr + 2] = START + #gdt0; // DSWORD[#idtr] = #idt_end - #idt; DSWORD[#idtr] = DSWORD[#idtr] - 1; DSDWORD[#idtr + 2] = START + #idt; //lgdt bx BX = #gdtr; $ db 0x3e, 0x0f, 0x01, 0x17 //lidt bx BX = #idtr; $ db 0x3e, 0x0f, 0x01, 0x1f // $ MOV EAX, CR0 $ OR AL, 1 $ MOV CR0, EAX // jump_pm32: $ db 0xEA $ dw 0 $ dw 0x10 } ?code32 TRUE void _1() { do_pm32: // $ MOV AX, 0x18 $ MOV DS, AX $ MOV SS, AX // $ MOV AX, 0x08 $ MOV ES, AX // @setup_pic(0x20, 0x28); ...
These snippets may seem a bit spaghetti code, but not because of some language defficiency but because I didn't look very far for them snippets.