Programmeren voor de Gigatron
Disclaimer: dit is geen officiële Gigatron-pagina en ik ben niet verantwoordelijk voor eventuele fouten. Deze pagina kan verouderd raken indien er een nieuwe revisie van de ROM wordt uitgebracht.
De CPU
De CPU die is geïmplementeerd met de TTL IC's van de Gigatron heeft een Harvard-architectuur. Dit betekent dat er geen gedeelde bus is voor het ROM en het RAM. In feite wordt het ROM alleen gebruikt om instructies op te slaan; er zijn geen instructies om het ROM direct te benaderen (hoewel er een slimme truc bestaat waarmee het toch mogelijk is om data uit het ROM te 'lezen').
De CPU is een 8-bit processor met een 14-bit program counter en een RAM-bereik van 15-bit. Hij beschikt over drie 8-bit registers en een 8-bit input en output.
CPU-instructies
Ik heb het programma gtemu.c herschreven zodat het uitprint wat de verschillende instructies precies doen in pseudo-C. Na diverse revisies resulteerde dit in de onderstaande tabel. De getallen van de rijen en kolommen moeten bij elkaar worden opgeteld om het instructienummer te verkrijgen. Ik heb de volgorde van de rijen aangepast zodat vergelijkbare (of identieke) instructies gegroepeerd zijn.
De functie hi retourneert het hoge byte van de waarde. Let op dat de waarde die gebruikt wordt om het RAM te benaderen, is begrensd tot 0x7fff, aangezien er slechts 32 kilobyte RAM beschikbaar is. De program counter wordt na elke instructie verhoogd, behalve bij instructies die de program counter zelf wijzigen. Wanneer een instructie twee bewerkingen uitvoert, worden deze gescheiden door een puntkomma.
| # 00 | # 20 | # 40 | # 60 | # 80 | # a0 | # c0 | # e0 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 00 | A = oper | A &= oper | A \ | = oper | A ^= oper | A += oper | A -= oper | RAM[oper] = oper | PC = (Y>>8)\ | oper | |||||||
| 04 | A = oper | A &= oper | A \ | = oper | A ^= oper | A += oper | A -= oper | RAM[X] = oper | if (A < 0) PC = hi(PC)\ | oper | |||||||
| 08 | A = oper | A &= oper | A \ | = oper | A ^= oper | A += oper | A -= oper | RAM[(Y>>8)\ | oper] = oper | if (A > 0) PC = hi(PC)\ | oper | ||||||
| 0c | A = oper | A &= oper | A \ | = oper | A ^= oper | A += oper | A -= oper | RAM[(Y>>8)\ | X] = oper | if (A != 0) PC = hi(PC)\ | oper | ||||||
| 10 | X = oper | X = A & oper | X = A \ | oper | X = A ^ oper | X = A + oper | X = A - oper | RAM[oper] = oper; X = A | if (A == 0) PC = hi(PC)\ | oper | |||||||
| 14 | Y = oper | Y = A & oper | Y = A \ | oper | Y = A ^ oper | Y = A + oper | Y = A - oper | RAM[oper] = oper; Y = A | if (A <= 0) PC = hi(PC)\ | oper | |||||||
| 18 | OUT = oper | OUT = A & oper | OUT = A \ | oper | OUT = A ^ oper | OUT = A + oper | OUT = A - oper | RAM[oper] = oper | if (A >= 0) PC = hi(PC)\ | oper | |||||||
| 1c | OUT = oper; X++ | OUT = A & oper; X++ | OUT = A \ | oper; X++ | OUT = A ^ oper; X++ | OUT = A + oper; X++ | OUT = A - oper; X++ | RAM[(Y>>8)\ | X++] = oper | PC = hi(PC)\ | oper | ||||||
| 01 | A = RAM[oper] | A &= RAM[oper] | A \ | = RAM[oper] | A ^= RAM[oper] | A += RAM[oper] | A -= RAM[oper] | RAM[oper] = undef | PC = (Y>>8)\ | RAM[oper] | |||||||
| 05 | A = RAM[X] | A &= RAM[X] | A \ | = RAM[X] | A ^= RAM[X] | A += RAM[X] | A -= RAM[X] | RAM[X] = undef | if (A < 0) PC = hi(PC)\ | RAM[oper] | |||||||
| 09 | A = RAM[(Y>>8)\ | oper] | A &= RAM[(Y>>8)\ | oper] | A \ | = RAM[(Y>>8)\ | oper] | A ^= RAM[(Y>>8)\ | oper] | A += RAM[(Y>>8)\ | oper] | A -= RAM[(Y>>8)\ | oper] | RAM[(Y>>8)\ | oper] = undef | if (A > 0) PC = hi(PC)\ | RAM[oper] |
| 0d | A = RAM[(Y>>8)\ | X] | A &= RAM[(Y>>8)\ | X] | A \ | = RAM[(Y>>8)\ | X] | A ^= RAM[(Y>>8)\ | X] | A += RAM[(Y>>8)\ | X] | A -= RAM[(Y>>8)\ | X] | RAM[(Y>>8)\ | X] = undef | if (A != 0) PC = hi(PC)\ | RAM[oper] |
| 11 | X = RAM[oper] | X = A & RAM[oper] | X = A \ | RAM[oper] | X = A ^ RAM[oper] | X = A + RAM[oper] | X = A - RAM[oper] | RAM[oper] = undef; X = A | if (A == 0) PC = hi(PC)\ | RAM[oper] | |||||||
| 15 | Y = RAM[oper] | Y = A & RAM[oper] | Y = A \ | RAM[oper] | Y = A ^ RAM[oper] | Y = A + RAM[oper] | Y = A - RAM[oper] | RAM[oper] = undef; Y = A | if (A <= 0) PC = hi(PC)\ | RAM[oper] | |||||||
| 19 | OUT = RAM[oper] | OUT = A & RAM[oper] | OUT = A \ | RAM[oper] | OUT = A ^ RAM[oper] | OUT = A + RAM[oper] | OUT = A - RAM[oper] | RAM[oper] = undef | if (A >= 0) PC = hi(PC)\ | RAM[oper] | |||||||
| 1d | OUT = RAM[(Y>>8)\ | X++] | OUT = A & RAM[(Y>>8)\ | X++] | OUT = A \ | RAM[(Y>>8)\ | X++] | OUT = A ^ RAM[(Y>>8)\ | X++] | OUT = A + RAM[(Y>>8)\ | X++] | OUT = A - RAM[(Y>>8)\ | X++] | RAM[(Y>>8)\ | X++] = undef | PC = hi(PC)\ | RAM[oper] |
| 02 | /nop/ | /nop/ | /nop/ | A = 0 | A *= 2 | A = 0 | RAM[oper] = A | PC = (Y>>8)\ | A | ||||||||
| 06 | /nop/ | /nop/ | /nop/ | A = 0 | A *= 2 | A = 0 | RAM[X] = A | if (A < 0) PC = hi(PC)\ | A | ||||||||
| 0a | /nop/ | /nop/ | /nop/ | A = 0 | A *= 2 | A = 0 | RAM[(Y>>8)\ | oper] = A | if (A > 0) PC = hi(PC)\ | A | |||||||
| 0e | /nop/ | /nop/ | /nop/ | A = 0 | A *= 2 | A = 0 | RAM[(Y>>8)\ | X] = A | if (A != 0) PC = hi(PC)\ | A | |||||||
| 12 | X = A | X = A | X = A | X = 0 | X = 2*A | X = 0 | RAM[oper] = A; X = A | if (A == 0) PC = hi(PC)\ | A | ||||||||
| 16 | Y = A | Y = A | Y = A | Y = 0 | Y = 2*A | Y = 0 | RAM[oper] = A; Y = A | if (A <= 0) PC = hi(PC)\ | A | ||||||||
| 1a | OUT = A | OUT = A | OUT = A | OUT = 0 | OUT = 2*A | OUT = 0 | RAM[oper] = A | if (A >= 0) PC = hi(PC)\ | A | ||||||||
| 1e | OUT = A; X++ | OUT = A; X++ | OUT = A; X++ | OUT = 0; X++ | OUT = 2*A; X++ | OUT = 0; X++ | RAM[(Y>>8)\ | X++] = A | PC = hi(PC)\ | A | |||||||
| 03 | A = IN | A &= IN | A \ | = IN | A ^= IN | A += IN | A -= IN | RAM[oper] = IN | PC = (Y>>8)\ | IN | |||||||
| 07 | A = IN | A &= IN | A \ | = IN | A ^= IN | A += IN | A -= IN | RAM[X] = IN | if (A < 0) PC = hi(PC)\ | IN | |||||||
| 0b | A = IN | A &= IN | A \ | = IN | A ^= IN | A += IN | A -= IN | RAM[(Y>>8)\ | oper] = IN | if (A > 0) PC = hi(PC)\ | IN | ||||||
| 0f | A = IN | A &= IN | A \ | = IN | A ^= IN | A += IN | A -= IN | RAM[(Y>>8)\ | X] = IN | if (A != 0) PC = hi(PC)\ | IN | ||||||
| 13 | X = IN | X = A & IN | X = A \ | IN | X = A ^ IN | X = A + IN | X = A - IN | RAM[oper] = IN; X = A | if (A == 0) PC = hi(PC)\ | IN | |||||||
| 17 | Y = IN | Y = A & IN | Y = A \ | IN | Y = A ^ IN | Y = A + IN | Y = A - IN | RAM[oper] = IN; Y = A | if (A <= 0) PC = hi(PC)\ | IN | |||||||
| 1b | OUT = IN | OUT = A & IN | OUT = A \ | IN | OUT = A ^ IN | OUT = A + IN | OUT = A - IN | RAM[oper] = IN | if (A >= 0) PC = hi(PC)\ | IN | |||||||
| 1f | OUT = IN; X++ | OUT = A & IN; X++ | OUT = A \ | IN; X++ | OUT = A ^ IN; X++ | OUT = A + IN; X++ | OUT = A - IN; X++ | RAM[(Y>>8)\ | X++] = IN | PC = hi(PC)\ | IN |
Vervolgens heb ik een programma geschreven om het bestand theloop.asm te analyseren en te ontdekken welke instructies daadwerkelijk worden gebruikt. Dit leverde de volgende resultaten op (waarbij $00 staat voor de operand):
| Inst | Aantal | Pseudo-C | Mnemonic | ||
|---|---|---|---|---|---|
| 02 | 586 | /nop/ | nop | ||
| 00 | 54305 | A = oper | ld $00 | ||
| 01 | 505 | A = RAM[oper] | ld [$00] | ||
| 03 | 1 | A = IN | ld in | ||
| 05 | 26 | A = RAM[X] | ld [x] | ||
| 09 | 2 | `A = RAM[(Y<<8)\ | oper]` | ld [y,$00] | |
| 0d | 32 | `A = RAM[(Y<<8)\ | X]` | ld [y,x] | |
| 10 | 1 | X = oper | ld $00,x | ||
| 11 | 27 | X = RAM[oper] | ld [$00],x | ||
| 12 | 11 | X = A | ld ac,x | ||
| 14 | 326 | Y = oper | ld $00,y | ||
| 15 | 19 | Y = RAM[oper] | ld [$00],y | ||
| 16 | 2 | Y = A | ld ac,y | ||
| 18 | 14 | OUT = oper | ld $00,out | ||
| 19 | 6 | OUT = RAM[oper] | ld [$00],out | ||
| 20 | 33 | A &= oper | anda $00 | ||
| 21 | 8 | A &= RAM[oper] | anda [$00] | ||
| 25 | 2 | A &= RAM[X] | anda [x] | ||
| 29 | 2 | `A &= RAM[(Y<<8)\ | oper]` | anda [y,$00] | |
| 30 | 9 | X = A & oper | anda $00,x | ||
| 40 | 14 | `A \ | = oper` | ora $00 | |
| 41 | 17 | `A \ | = RAM[oper]` | ora [$00] | |
| 45 | 3 | `A \ | = RAM[X]` | ora [x] | |
| 50 | 6 | `X = A \ | oper` | ora $00,x | |
| 5d | 3 | `OUT = A \ | RAM[(Y<<8)\ | X++]` | ora [y,x++],out |
| 60 | 16 | A ^= oper | xora $bf | ||
| 61 | 11 | A ^= RAM[oper] | xora [$00] | ||
| 69 | 5 | `A ^= RAM[(Y<<8)\ | oper]` | xora [y,$00] | |
| 80 | 402 | A += oper | adda $00 | ||
| 81 | 28 | A += RAM[oper] | adda [$00] | ||
| 82 | 36 | A *= 2 | adda ac | ||
| 85 | 2 | A += RAM[X] | adda [x] | ||
| 89 | 6 | `A += RAM[(Y<<8)\ | oper]` | adda [y,$00] | |
| 8d | 4 | `A += RAM[(Y<<8)\ | X]` | adda [y,x] | |
| 90 | 11 | X = A + oper | adda $00,x | ||
| 91 | 1 | X = A + RAM[oper] | adda [$00],x | ||
| 92 | 2 | X = 2*A | adda ac,x | ||
| 95 | 1 | Y = A + RAM[oper] | adda [$00],y | ||
| a0 | 28 | A -= oper | suba $00 | ||
| a1 | 3 | A -= RAM[oper] | suba [$00] | ||
| a5 | 5 | A -= RAM[X] | suba [x] | ||
| b0 | 3 | X = A - oper | suba $00,x | ||
| c0 | 4 | RAM[oper] = oper | st $00,[$00] | ||
| c2 | 662 | RAM[oper] = A | st [$00] | ||
| c3 | 2 | RAM[oper] = IN | st in,[$00] | ||
| c6 | 8 | RAM[X] = A | st [x] | ||
| ca | 6 | `RAM[(Y<<8)\ | oper] = A` | st [y,$00] | |
| ce | 9 | `RAM[(Y<<8)\ | X] = A` | st [y,x] | |
| d2 | 7 | RAM[oper] = A; X = A | st [$00],x | ||
| d6 | 8 | RAM[oper] = A; Y = A | st [$00],y | ||
| de | 27 | `RAM[(Y<<8)\ | X++] = A` | st [y,x++] | |
| dc | 52 | `RAM[(Y<<8)\ | X++] = oper` | st $00,[y,x++] | |
| e0 | 314 | `PC = (Y<<8)\ | oper` | jmp y,$00 | |
| e1 | 2 | `PC = (Y<<8)\ | RAM[oper]` | jmp y,[$00] | |
| e2 | 13 | `PC = (Y<<8)\ | A` | jmp y,ac | |
| e4 | 3 | `if (A > 0) PC = hi(PC)\ | oper` | bgt $00 | |
| e8 | 14 | `if (A < 0) PC = hi(PC)\ | oper` | blt $00 | |
| ec | 30 | `if (A != 0) PC = hi(PC)\ | oper` | bne $00 | |
| f0 | 10 | `if (A == 0) PC = hi(PC)\ | oper` | beq $00 | |
| f4 | 5 | `if (A >= 0) PC = hi(PC)\ | oper` | bge $00 | |
| f8 | 2 | `if (A <= 0) PC = hi(PC)\ | oper` | ble $00 | |
| fc | 497 | `PC = hi(PC)\ | oper` | bra $00 | |
| fd | 2 | `PC = hi(PC)\ | RAM[oper]` | bra [$00] | |
| fe | 612 | `PC = hi(PC)\ | A` | bra ac |
De vCPU
De virtuele CPU (vCPU) heeft een Von Neumann-architectuur.
vCPU-instructies
Het ROM implementeert een virtuele 16-bit CPU die draait wanneer de fysieke CPU niet bezig is met het genereren van het VGA-signaal. In het begin begreep ik niet hoe deze instructies gecodeerd waren, maar later ontdekte ik dat ze simpelweg een offset hebben in een van de geheugensegmenten. Dit betekent dat er feitelijk 256 instructies zijn geïmplementeerd door de vCPU, waarvan vele niets nuttigs doen (of de Gigatron kunnen laten crashen).
De vCPU beschikt over:
- Een accumulator (vA, opgeslagen op geheugenlocatie
0x18en0x19). - Een program counter (vPC, opgeslagen op locatie
0x16en0x17). - Een stack pointer (vSP, opgeslagen op locatie
0x1c). - Een retouradres (vLR, opgeslagen op locatie
0x1aen0x1b).
De instructies kunnen in pseudo-C als volgt worden beschreven (opcodes tussen haakjes):
ST(0x5e) oper RAM[oper] = lo(vA);
STW(0x2b) oper RAM[oper] = lo(vA); RAM[oper+1] = hi(vA);
STLW(0xec) oper RAM[vSP+oper] = lo(vA); RAM[vSP+oper+1] = hi(vA);
LD(0x1a) oper vA = RAM[oper];
LDI(0x59) oper vA = oper;
LDWI(0x11) op1 op2 vA = op1 | (op2<<8);
LDW(0x21) oper vA = RAM[oper] | (RAM[oper+1]<<8);
LDLW(0xee) oper vA = RAM[vSP+oper] | (RAM[vSP+oper+1]<<8);
ADDI(0xe3) oper vA += oper;
ADDW(0x99) oper vA += RAM[oper] | (RAM[oper+1]<<8);
SUBI(0xe6) oper vA -= oper;
SUBW(0xb8) oper vA -= RAM[oper] | (RAM[oper+1]<<8);
ANDI(0x83) oper vA &= oper;
ANDW(0xf8) oper vA &= RAM[oper] | (RAM[oper+1]<<8);
ORI(0x88) oper vA |= oper;
ORW(0xfa) oper vA |= RAM[oper] | (RAM[oper+1]<<8);
XORI(0x8c) oper vA ^= oper;
XORW(0xfc) oper vA ^= RAM[oper] | (RAM[oper+1]<<8);
INC(0x93) oper RAM[oper]++;
PEEK(0xad) vA = RAM[vA];
DEEK(0xf6) vA = RAM[vA] | (RAM[vA+1]<<8);
POKE(0xf3) oper RAM[RAM[oper]|(RAM[oper+1]<<8)] = lo(vA);
DOKE(0xf3) oper addr = RAM[oper]|(RAM[oper+1]<<8); RAM[addr] = lo(vA); RAM[addr+1] = hi(vA);
LSLW(0xe9) vA = vA << 1;
BCC(0x35) EQ(0x3f) addr if (vA == 0) vPC = hi(vPC)|addr;
BCC(0x35) GT(0x4d) addr if (vA > 0) vPC = hi(vPC)|addr;
BCC(0x35) LT(0x50) addr if (vA < 0) vPC = hi(vPC)|addr;
BCC(0x35) GE(0x53) addr if (vA >= 0) vPC = hi(vPC)|addr;
BCC(0x35) LE(0x56) addr if (vA <= 0) vPC = hi(vPC)|addr;
BCC(0x35) NE(0x73) addr if (vA != 0) vPC = hi(vPC)|addr;
BRA(0x90) vPC = hi(vPC)|addr;
LUP((0x7f) oper vA = ROM[vA | (oper<<8)];
CALL(0xcf) oper vLR = vPC+2; vPC = RAM[oper] | (RAM[oper+1]<<8);
RET(0xff) vPC = vLR-2;
PUSH(0x75) RAM[--vSP] = lo(vLR); RAM[--vSP] = hi(vLR);
POP(0x63) vLR = RAM[vSP] | (RAM[vSP+1]<<8); vSP += 2;
ALLOC(0xdf) oper vSP += oper;
DEF(0xcd) oper vA = vCP+2; vCP = hi(vCP)|oper;
SYS(0xb4) ticks syscall(RAM[0x22] | (RAM[0x23]<<8));
De SYS-instructie voert de systeemaanroep uit waarvan het adres is opgeslagen in sysFn (locaties 0x22 en 0x23). De argumenten voor de aanroep staan in sysArgs (locaties 0x24 tot 0x2b).
Systeemaanroepen:
- SYSRandom34 (
0x04a7) - SYSLSRW730 (
0x04b9) - SYSLSRW824 (
0x04c6) - SYSLSLW824 (
0x04cd) - SYSDraw430 (
0x04d4) - SYSVDrawBits134 (
0x04e1) - SYSLSRW148 (
0x0600) - SYSLSRW252 (
0x0619) - SYSLSRW352 (
0x0636) - SYSLSRW450 (
0x0652) - SYSLSRW550 (
0x066d) - SYSLSRW648 (
0x0687) - SYSLSLW446 (
0x06a0) - SYSRead340 (
0x06c0) - SYSPayloadCopy34 (
0x06e7) - SYSRacerUpdateVideoX40 (
0xd700) - SYSRacerUpdateVideoY40 (
0xd719) - SYSLoaderProcessInput48 (
0xd731) - SYSReset36 (
0x009a) - SYSExec88 (
0x00ad) - SYSOut22 (
0x00f4) - SYSIn24 (
0x00f9) - SYSNextByteIn32 (
0x02e9)
Mapping van GLC naar vCPU-instructies
De onderstaande tabel beschrijft de koppeling tussen GLC-taalelementen en vCPU-instructies.
| GLC Element | vCPU Instructie | |
|---|---|---|
if<>0 | BCC EQ addr | |
if=;0 | BCC NE addr | |
if>=0 | BCC LT addr | |
if<=0 | BCC GT addr | |
if>0 | BCC LE addr | |
if<0 | BCC GE addr | |
if<>0loop | BCC EQ addr | |
if=;0loop | BCC NE oper | |
if>=0loop | BCC LT addr | |
if<=0loop | BCC GT addr | |
if>0loop | BCC LE addr | |
if<0lopp | BCC GE addr | |
else | BRA addr | |
push | PUSH | |
pop | POP | |
ret | RET | |
call | CALL oper | |
peek | PEEK | |
X | LDW addr(X) | |
[0..255] | LDI oper | |
[256..65,535] | LDWI oper oper | |
[0..255]; | LDW oper | |
X= | STW addr(X) | |
[0..255]= | STW oper | |
X+ | ADDW addr(X) | |
[0..255]+ | ADDI oper | |
X;- | SUBW addr(X) | |
[0..255]- | SUBI oper | |
X& | ANDW addr(X) | |
[0..255]& | ANDI oper | |
| `X\ | ` | ORIW addr(X) |
| `[0..255]\ | ` | ORI oper |
X^ | XORIW addr(X) | |
[0..255]^ | XORI oper | |
[0..255]<< | LSLW (repeated) | |
[0..255]-- | ALLOC (-oper&255) | |
[0..255]++ | ALLOC oper | |
[0..255]%= | STLW oper | |
[0..255]%= | LDLW oper | |
[0..255]# | oper | |
[0..255]? | LUP oper | |
[0..255]. | ST oper | |
[0..255], | LD oper | |
X. | POKE addr(X) | |
X< | ST addr(X) | |
X> | ST addr(X)+1 | |
X, | LDW addr(X) PEEK | |
[0..255]<++ | INC oper | |
X<++ | INC addr(X) | |
X>++ | INC addr(X)+1 | |
X<, | LD addr(X) | |
X>, | LD addr(X)+1 | |
X! | CALL addr(X) |
Grammatica voor gt-C
Hieronder volgt de grammatica voor gt-C, een zeer beperkte subset van C, die dient als basis voor het schrijven van een compiler.
primary_expr
: ident
| int
| char
| "(" expr ")"
.
postfix_expr
: postfix_expr "[" expr "]" [array]
| postfix_expr "(" assignment_expr LIST OPT ")" [call]
| postfix_expr "++" [post_inc]
| postfix_expr "--" [post_dec]
| primary_expr
.
unary_expr
: "++" unary_expr [pre_inc]
| "--" unary_expr [pre_dec]
| "-" cast_expr [min]
| "~" cast_expr [invert]
| "!" cast_expr [not]
| postfix_expr
.
cast_expr
: "(" simple_type ")" cast_expr [cast]
| unary_expr
.
l_expr2 : l_expr2 "+" cast_expr [add]
| l_expr2 "-" cast_expr [sub]
| cast_expr
.
l_expr3 : l_expr3 "<<" l_expr2 [ls]
| l_expr3 ">>" l_expr2 [rs]
| l_expr2
.
l_expr4 : l_expr4 "<=" l_expr3 [le]
| l_expr4 ">=" l_expr3 [ge]
| l_expr4 "<" l_expr3 [lt]
| l_expr4 ">" l_expr3 [gt]
| l_expr4 "==" l_expr3 [eq]
| l_expr4 "!=" l_expr3 [ne]
| l_expr3
.
l_expr5 : l_expr5 "^" l_expr4 [bexor] | l_expr4 .
l_expr6 : l_expr6 "&" l_expr5 [band] | l_expr5 .
l_expr7 : l_expr7 "|" l_expr6 [bor] | l_expr6 .
l_expr8 : l_expr8 "&&" l_expr7 [land] | l_expr7 .
l_expr9 : l_expr9 "||" l_expr8 [lor] | l_expr8 .
conditional_expr
: l_expr9 "?" l_expr9 ":" conditional_expr [if_expr]
| l_expr9
.
assignment_expr
: unary_expr "=" assignment_expr [ass]
| unary_expr "+=" assignment_expr [add_ass]
| unary_expr "-=" assignment_expr [sub_ass]
| unary_expr "<<=" assignment_expr [sl_ass]
| unary_expr ">>=" assignment_expr [sr_ass]
| unary_expr "&=" assignment_expr [and_ass]
| unary_expr "|=" assignment_expr [or_ass]
| unary_expr "^=" assignment_expr [exor_ass]
| conditional_expr
.
expr : assignment_expr LIST.
simple_type
: "word" [word]
| "byte" [byte]
.
func_decl
: ("void"[void]|simple_type) ident "(" (simple_type ident)LIST OPT ")"
"{" statement SEQ OPT "}" [funcdef]
.
statement
: "{" statement SEQ OPT "}"
| simple_type ident ("=" conditional_expr) OPT ";" [vardecl]
| expr OPT ";" [expr]
| "if" "(" expr ")" statement ("else" statement) OPT [if]
| "while" "(" expr ")" statement [while]
| "do" statement "while" "(" expr ")" ";" [do]
| "for" "(" (simple_type OPT ident "=" expr)OPT ";"
expr OPT ";"
expr OPT ")" statement [for]
| "continue" ";" [cont]
| "break" ";" [break]
| "return" expr OPT ";" [ret]
.
root : ( func_decl | statement ) SEQ OPT eof
.
Eerste doelprogramma
Het eerste programma waar ik aan ga werken, is een implementatie van Conway's Game of Life. Dit programma maakt geen gebruik van alle constructies uit de bovenstaande grammatica.
// Clear the screen
for (word h = 0; h < 200; h++)
for (word v = 0; v < 200; v++)
setScreen(h, v, 0);
// Initialize some random part
for (word h = 90; h < 110; h++)
for (word v = 90; v < 110; v++)
if (random() < 110)
setScreen(h, v, 0x3f);
while (true)
{
for (word h = 1; h < 199; h++)
for (word v = 1; v < 199; v++)
{
word c = 0;
word vk = v - 1;
if (getScreen(h-1,vk) < 0) c++;
vk++;
if (getScreen(h-1,vk) < 0) c++;
vk++;
if (getScreen(h-1,vk) < 0) c++;
vk -= 2;
if (getScreen(h,vk) < 0) c++;
vk++;
word m = getScreen(h, vk) & 0x3f;
vk++;
if (getScreen(h,vk) & 0x3f != 0) c++;
vk -= 2;
if (getScreen(h+1,vk) & 0x3f != 0) c++;
vk++;
if (getScreen(h+1,vk) & 0x3f != 0) c++;
vk++;
if (getScreen(h+1,vk) & 0x3f != 0) c++;
if (m != 0)
{
if (c == 2 || c == 3)
m = 0xff;
else
m = 0xd0;
}
else
{
if (c == 3)
m = 0x3f;
else
m = 0;
}
setScreen(h, v, m);
}
}
Groetjes,