Commit 0c54225b authored by Russ Cox's avatar Russ Cox

remove nacl

The recent linker changes broke NaCl support
a month ago, and there are no known users of it.

The NaCl code can always be recovered from the
repository history.

R=adg, r
CC=golang-dev
https://golang.org/cl/3671042
parent 85f5bb82
......@@ -89,8 +89,6 @@ Safe compilation mode: generate code that is guaranteed not to obtain an invalid
<li>
Gccgo: garbage collection.
<li>
Native Client (NaCl) support.
<li>
SWIG support.
<li>
Simpler semicolon rules.
......
......@@ -62,7 +62,7 @@ support for segmented stacks, and a strong goroutine implementation.
</p>
<p>
The compilers can target the FreeBSD, Linux, Native Client,
The compilers can target the FreeBSD, Linux,
and OS X (a.k.a. Darwin) operating systems.
(A port to Microsoft Windows is in progress but incomplete. See the
<a href="http://code.google.com/p/go/wiki/WindowsPort">Windows Port</a>
......@@ -340,7 +340,6 @@ to override the defaults.
Choices for <code>$GOOS</code> are <code>linux</code>,
<code>freebsd</code>,
<code>darwin</code> (Mac OS X 10.5 or 10.6),
<code>nacl</code> (Native Client, an incomplete port),
and <code>windows</code> (Windows, an incomplete port).
Choices for <code>$GOARCH</code> are <code>amd64</code> (64-bit x86, the most mature port),
<code>386</code> (32-bit x86), and
......@@ -372,9 +371,6 @@ to override the defaults.
<td></td><td><code>linux</code></td> <td><code>arm</code></td> <td><i>incomplete</i></td>
</tr>
<tr>
<td></td><td><code>nacl</code></td> <td><code>386</code></td>
</tr>
<tr>
<td></td><td><code>windows</code></td> <td><code>386</code></td> <td><i>incomplete</i></td>
</tr>
</table>
......
......@@ -32,12 +32,11 @@ endif
ifeq ($(GOOS),darwin)
else ifeq ($(GOOS),freebsd)
else ifeq ($(GOOS),linux)
else ifeq ($(GOOS),nacl)
else ifeq ($(GOOS),tiny)
else ifeq ($(GOOS),plan9)
else ifeq ($(GOOS),windows)
else
$(error Invalid $$GOOS '$(GOOS)'; must be darwin, freebsd, linux, nacl, tiny, plan9, or windows)
$(error Invalid $$GOOS '$(GOOS)'; must be darwin, freebsd, linux, plan9, tiny, or windows)
endif
ifeq ($(GOHOSTARCH),)
......
#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# TODO(rsc): delete in favor of all.bash once nacl support is complete
export GOARCH=386
export GOOS=nacl
export GORUN=${GORUN:-$GOROOT/misc/nacl/naclrun}
set -e
bash make.bash
xcd() {
echo
echo --- cd $1
builtin cd $1
}
(xcd pkg
make install
make test
) || exit $?
(xcd pkg/exp/nacl/srpc
make clean
make install
) || exit $?
(xcd pkg/exp/nacl/av
make clean
make install
) || exit $?
(xcd pkg/exp/4s
make clean
make
) || exit $?
(xcd pkg/exp/spacewar
make clean
make
) || exit $?
(xcd ../test
./run
) || exit $?
......@@ -535,8 +535,6 @@ asmb(void)
for(sect=segtext.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segrodata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
......
......@@ -415,7 +415,7 @@ addpltsym(Sym *s)
static void
addgotsym(Sym *s)
{
Sym *got, *rela, *indir;
Sym *got, *rela;
if(s->got >= 0)
return;
......@@ -976,8 +976,6 @@ asmb(void)
diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
for(sect=segtext.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segrodata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
......
......@@ -8,7 +8,6 @@
#include "opt.h"
static Prog *pret;
static Node *naclnop;
void
compile(Node *fn)
......@@ -24,7 +23,6 @@ compile(Node *fn)
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
naclnop = sysfunc("naclnop");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
......@@ -96,16 +94,8 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
ginit();
if(hasdefer) {
// On Native client, insert call to no-op function
// to force alignment immediately before call to deferreturn,
// so that when jmpdefer subtracts 5 from the second CALL's
// return address and then the return masks off the low bits,
// we'll back up to the NOPs immediately after the dummy CALL.
if(strcmp(getgoos(), "nacl") == 0)
ginscall(naclnop, 0);
if(hasdefer)
ginscall(deferreturn, 0);
}
if(curfn->exit)
genlist(curfn->exit);
gclean();
......
......@@ -539,8 +539,6 @@ doelf(void)
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
addstring(shstrtab, ".elfdata");
if(HEADTYPE == 8)
addstring(shstrtab, ".closure");
addstring(shstrtab, ".rodata");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
......@@ -674,8 +672,6 @@ asmb(void)
sect = segtext.sect;
seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
codeblk(sect->vaddr, sect->len);
// TODO: NaCl: pad with HLT
/* output read-only data in text segment */
sect = segtext.sect->next;
......@@ -889,7 +885,7 @@ asmb(void)
Elfput:
/* elf 386 */
if(HEADTYPE == 8 || HEADTYPE == 11)
if(HEADTYPE == 11)
debug['d'] = 1;
eh = getElfEhdr();
......@@ -901,17 +897,14 @@ asmb(void)
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
/* program header info - but not on native client */
pph = nil;
if(HEADTYPE != 8) {
pph = newElfPhdr();
pph->type = PT_PHDR;
pph->flags = PF_R + PF_X;
pph->off = eh->ehsize;
pph->vaddr = INITTEXT - HEADR + pph->off;
pph->paddr = INITTEXT - HEADR + pph->off;
pph->align = INITRND;
}
/* program header info */
pph = newElfPhdr();
pph->type = PT_PHDR;
pph->flags = PF_R + PF_X;
pph->off = eh->ehsize;
pph->vaddr = INITTEXT - HEADR + pph->off;
pph->paddr = INITTEXT - HEADR + pph->off;
pph->align = INITRND;
if(!debug['d']) {
/* interpreter */
......@@ -935,8 +928,6 @@ asmb(void)
}
elfphload(&segtext);
if(segrodata.len > 0)
elfphload(&segrodata);
elfphload(&segdata);
/* Dynamic linking sections */
......@@ -1038,8 +1029,6 @@ asmb(void)
diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
for(sect=segtext.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segrodata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
......@@ -1073,11 +1062,6 @@ asmb(void)
eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT;
switch(HEADTYPE) {
case 8:
eh->ident[EI_OSABI] = ELFOSABI_NACL;
eh->ident[EI_ABIVERSION] = 7;
eh->flags = 0x200000; // aligned mod 32
break;
case 9:
eh->ident[EI_OSABI] = 9;
break;
......
......@@ -321,7 +321,6 @@ EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
EXTERN Sym* textp;
EXTERN int32 textpad;
EXTERN int32 textsize;
EXTERN int version;
EXTERN Prog zprg;
......
......@@ -55,8 +55,10 @@ char *thestring = "386";
* -H4 -Tx -Rx is fake MS-DOS .EXE
* -H6 -Tx -Rx is Apple Mach-O
* -H7 -Tx -Rx is Linux ELF32
* -H8 -Tx -Rx is Google Native Client
* -H8 -Tx -Rx was Google Native Client
* -H9 -Tx -Rx is FreeBSD ELF32
* -H10 -Tx -Rx is MS Windows PE
* -H11 -Tx -Rx is tiny (os image)
*/
void
......@@ -133,9 +135,6 @@ main(int argc, char *argv[])
if(strcmp(goos, "darwin") == 0)
HEADTYPE = 6;
else
if(strcmp(goos, "nacl") == 0)
HEADTYPE = 8;
else
if(strcmp(goos, "freebsd") == 0)
HEADTYPE = 9;
else
......@@ -248,21 +247,6 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
case 8: /* native client elf32 executable */
elfinit();
HEADR = 4096;
if(INITTEXT == -1)
INITTEXT = 0x20000;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 65536;
// 512 kB of address space for closures.
// (Doesn't take any space in the binary file.)
// Closures are 64 bytes each, so this is 8,192 closures.
textpad = 512*1024;
break;
case 10: /* PE executable */
peinit();
HEADR = PEFILEHEADR;
......
......@@ -822,22 +822,6 @@ subreg(Prog *p, int from, int to)
print("%P\n", p);
}
// nacl RET:
// POPL BX
// ANDL BX, $~31
// JMP BX
uchar naclret[] = { 0x5b, 0x83, 0xe3, ~31, 0xff, 0xe3 };
// nacl JMP BX:
// ANDL BX, $~31
// JMP BX
uchar nacljmpbx[] = { 0x83, 0xe3, ~31, 0xff, 0xe3 };
// nacl CALL BX:
// ANDL BX, $~31
// CALL BX
uchar naclcallbx[] = { 0x83, 0xe3, ~31, 0xff, 0xd3 };
void
doasm(Prog *p)
{
......@@ -906,12 +890,6 @@ found:
break;
case Zlit:
if(HEADTYPE == 8 && p->as == ARET) {
// native client return.
for(z=0; z<sizeof(naclret); z++)
*andptr++ = naclret[z];
break;
}
for(; op = o->op[z]; z++)
*andptr++ = op;
break;
......@@ -945,42 +923,6 @@ found:
break;
case Zo_m:
if(HEADTYPE == 8) {
Adr a;
switch(p->as) {
case AJMP:
if(p->to.type < D_AX || p->to.type > D_DI)
diag("indirect jmp must use register in native client");
// ANDL $~31, REG
*andptr++ = 0x83;
asmand(&p->to, 04);
*andptr++ = ~31;
// JMP REG
*andptr++ = 0xFF;
asmand(&p->to, 04);
return;
case ACALL:
a = p->to;
// native client indirect call
if(a.type < D_AX || a.type > D_DI) {
// MOVL target into BX
*andptr++ = 0x8b;
asmand(&p->to, reg[D_BX]);
memset(&a, 0, sizeof a);
a.type = D_BX;
}
// ANDL $~31, REG
*andptr++ = 0x83;
asmand(&a, 04);
*andptr++ = ~31;
// CALL REG
*andptr++ = 0xFF;
asmand(&a, 02);
return;
}
}
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
break;
......@@ -1004,12 +946,6 @@ found:
else
a = &p->to;
v = vaddr(a, nil);
if(HEADTYPE == 8 && p->as == AINT && v == 3) {
// native client disallows all INT instructions.
// translate INT $3 to HLT.
*andptr++ = 0xf4;
break;
}
*andptr++ = op;
*andptr++ = v;
break;
......@@ -1380,51 +1316,8 @@ mfound:
void
asmins(Prog *p)
{
if(HEADTYPE == 8) {
ulong npc;
static Prog *prefix;
// TODO: adjust relocations, like 6l does for rex prefix
// native client
// - pad indirect jump targets (aka ATEXT) to 32-byte boundary
// - instructions cannot cross 32-byte boundary
// - end of call (return address) must be on 32-byte boundary
if(p->as == ATEXT)
p->pc += 31 & -p->pc;
if(p->as == ACALL) {
// must end on 32-byte boundary.
// doasm to find out how long the CALL encoding is.
andptr = and;
doasm(p);
npc = p->pc + (andptr - and);
p->pc += 31 & -npc;
}
if(p->as == AREP || p->as == AREPN) {
// save prefix for next instruction,
// so that inserted NOPs do not split (e.g.) REP / MOVSL sequence.
prefix = p;
andptr = and;
return;
}
andptr = and;
if(prefix)
doasm(prefix);
doasm(p);
npc = p->pc + (andptr - and);
if(andptr > and && (p->pc&~31) != ((npc-1)&~31)) {
// crossed 32-byte boundary; pad to boundary and try again
p->pc += 31 & -p->pc;
andptr = and;
if(prefix)
doasm(prefix);
doasm(p);
}
prefix = nil;
} else {
andptr = and;
doasm(p);
}
andptr = and;
doasm(p);
if(andptr > and+sizeof and) {
print("and[] is too short - %d byte instruction\n", andptr - and);
errorexit();
......
......@@ -400,6 +400,7 @@ dpcheck(Node *n)
i = l->param;
b = n->right;
a = Z;
while(i > 0) {
b = nextarg(b, &a);
i--;
......
......@@ -95,7 +95,6 @@ EXTERN char* thestring;
EXTERN Segment segtext;
EXTERN Segment segdata;
EXTERN Segment segrodata; // NaCl only
EXTERN Segment segsym;
void addlib(char *src, char *obj);
......
......@@ -186,27 +186,6 @@ ifeq ($(DISABLE_NET_TESTS),1)
NOTEST+=http net
endif
# Disable tests that NaCl cannot run yet.
ifeq ($(GOOS),nacl)
NOTEST+=archive/tar # no pipe
NOTEST+=archive/zip # no pread
NOTEST+=debug/dwarf # no pread
NOTEST+=debug/macho # no pread
NOTEST+=debug/elf # no pread
NOTEST+=exec # no pipe
NOTEST+=http # no network
NOTEST+=log # no runtime.Caller
NOTEST+=net # no network
NOTEST+=netchan # no network
NOTEST+=os # many things unimplemented
NOTEST+=os/signal # no signals
NOTEST+=path # tree walking does not work
NOTEST+=rpc # no network
NOTEST+=syslog # no network
NOTEST+=time # no syscall.Kill, syscall.SIGCHLD for sleep tests
NOTEST+=websocket # no network
endif
# Disable tests that windows cannot run yet.
ifeq ($(GOOS),windows)
NOTEST+=os/signal # no signals
......
......@@ -18,9 +18,6 @@ GOFILES_darwin=\
GOFILES_linux=\
rand_unix.go\
GOFILES_nacl=\
rand_unix.go\
GOFILES_windows=\
rand_windows.go\
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proc
import (
"os"
"syscall"
)
// Process tracing is not supported on Native Client.
func Attach(pid int) (Process, os.Error) {
return nil, os.NewSyscallError("ptrace", syscall.ENACL)
}
func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
return nil, os.NewSyscallError("fork/exec", syscall.ENACL)
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proc
......@@ -17,9 +17,6 @@ GOFILES_darwin=\
GOFILES_linux=\
lp_unix.go\
GOFILES_nacl=\
lp_unix.go\
GOFILES_windows=\
lp_windows.go\
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This is a simple demo of Go running under Native Client.
// It is a tetris clone built on top of the exp/nacl/av and exp/draw
// packages.
//
// See ../nacl/README for how to run it.
package main
import (
"exp/nacl/av"
"exp/nacl/srpc"
"log"
"runtime"
"os"
)
var sndc chan []uint16
func main() {
// Native Client requires that some calls are issued
// consistently by the same OS thread.
runtime.LockOSThread()
if srpc.Enabled() {
go srpc.ServeRuntime()
}
args := os.Args
p := pieces4
if len(args) > 1 && args[1] == "-5" {
p = pieces5
}
dx, dy := 500, 500
w, err := av.Init(av.SubsystemVideo|av.SubsystemAudio, dx, dy)
if err != nil {
log.Exit(err)
}
sndc = make(chan []uint16, 10)
go audioServer()
Play(p, w)
}
func audioServer() {
// Native Client requires that all audio calls
// original from a single OS thread.
runtime.LockOSThread()
n, err := av.AudioStream(nil)
if err != nil {
log.Exit(err)
}
for {
b := <-sndc
for len(b)*2 >= n {
var a []uint16
a, b = b[0:n/2], b[n/2:]
n, err = av.AudioStream(a)
if err != nil {
log.Exit(err)
}
println(n, len(b)*2)
}
a := make([]uint16, n/2)
copy(a, b)
n, err = av.AudioStream(a)
}
}
func PlaySound(b []uint16) { sndc <- b }
var whoosh = []uint16{
// Insert your favorite sound samples here.
}
<h1>games/4s</h1>
<table><tr><td valign=top>
<embed name="nacl_module" id="pluginobj" src="8.out" type="application/x-nacl-srpc" width=400 height=600>
<td valign=top>
This is a simple block stacking game, a port of Plan 9's
<a href="http://plan9.bell-labs.com/magic/man2html/1/games">games/4s</a>
<br><br>
To play using the keyboard:
as the blocks fall, the <i>a</i>, <i>s</i>, <i>d</i>, and <i>f</i> keys
move the block left, rotate the block left, rotate the block right,
anad move the block right, respectively.
To drop a block, type the space key.
<b>You may need to click on the game window to
focus the keyboard on it.</b>
<br><br>
To play using the mouse:
as the blocks fall, moving the mouse horizontally positions
the block; left or right clicks rotate the block left or right.
A middle click drops the block.
(Unfortunately, some environments seem to intercept
the middle click before it gets to Native Client.)
<br><br>
To pause the game, type <i>z</i>, <i>p</i>, or the escape key.
</table>
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Hack to produce a binary that defaults to 5s.
package main
func init() { pieces4 = pieces5 }
<h1>games/5s</h1>
<table><tr><td valign=top>
<embed name="nacl_module" id="pluginobj" src="8.5s" type="application/x-nacl-srpc" width=400 height=600>
<td valign=top>
This is a simple block stacking game, a port of Plan 9's
<a href="http://plan9.bell-labs.com/magic/man2html/1/games">games/5s</a>
<br><br>
To play using the keyboard:
as the blocks fall, the <i>a</i>, <i>s</i>, <i>d</i>, and <i>f</i> keys
move the block left, rotate the block left, rotate the block right,
anad move the block right, respectively.
To drop a block, type the space key.
<b>You may need to click on the game window to
focus the keyboard on it.</b>
<br><br>
To play using the mouse:
as the blocks fall, moving the mouse horizontally positions
the block; left or right clicks rotate the block left or right.
A middle click drops the block.
(Unfortunately, some environments seem to intercept
the middle click before it gets to Native Client.)
<br><br>
To pause the game, type <i>z</i>, <i>p</i>, or the escape key.
</table>
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
all: 8.out 8.5s
4s.8: 4s.go data.go xs.go
8g 4s.go data.go xs.go
5s.8: 5s.go 4s.go data.go xs.go
8g 5s.go 4s.go data.go xs.go
8.out: 4s.8
8l 4s.8
8.5s: 5s.8
8l -o 8.5s 5s.8
clean:
rm -f *.8 8.out
// games/4s - a tetris clone
//
// Derived from Plan 9's /sys/src/games/xs.c
// http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c
//
// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
// Portions Copyright 2009 The Go Authors. All Rights Reserved.
// Distributed under the terms of the Lucent Public License Version 1.02
// See http://plan9.bell-labs.com/plan9/license.html
package main
import . "image"
var pieces4 = []Piece{
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{0, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
{1, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
{2, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
{3, 3, Point{2, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}, nil, nil},
{0, 1, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
{1, 1, Point{2, 3}, []Point{{1, 0}, {0, 1}, {0, 1}, {-1, 0}}, nil, nil},
{2, 1, Point{3, 2}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}}, nil, nil},
{3, 1, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
{0, 2, Point{3, 2}, []Point{{0, 1}, {1, 0}, {1, 0}, {0, -1}}, nil, nil},
{1, 2, Point{2, 3}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
{2, 2, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
{3, 2, Point{2, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
{0, 4, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{1, 4, Point{2, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {0, 1}}, nil, nil},
{2, 4, Point{3, 2}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}}, nil, nil},
{3, 4, Point{2, 3}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, -1}}, nil, nil},
{0, 5, Point{3, 2}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
{1, 5, Point{2, 3}, []Point{{1, 0}, {0, 1}, {-1, 0}, {0, 1}}, nil, nil},
{2, 5, Point{3, 2}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
{3, 5, Point{2, 3}, []Point{{1, 0}, {0, 1}, {-1, 0}, {0, 1}}, nil, nil},
{0, 6, Point{3, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {1, 0}}, nil, nil},
{1, 6, Point{2, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
{2, 6, Point{3, 2}, []Point{{0, 1}, {1, 0}, {0, -1}, {1, 0}}, nil, nil},
{3, 6, Point{2, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
}
var pieces5 = []Piece{
{0, 1, Point{5, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{1, 1, Point{1, 5}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{2, 1, Point{5, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 1, Point{1, 5}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{0, 0, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
{1, 0, Point{2, 4}, []Point{{1, 0}, {0, 1}, {0, 1}, {0, 1}, {-1, 0}}, nil, nil},
{2, 0, Point{4, 2}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{2, 4}, []Point{{0, 0}, {1, 0}, {-1, 1}, {0, 1}, {0, 1}}, nil, nil},
{0, 2, Point{4, 2}, []Point{{0, 0}, {0, 1}, {1, -1}, {1, 0}, {1, 0}}, nil, nil},
{1, 2, Point{2, 4}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{2, 2, Point{4, 2}, []Point{{0, 1}, {1, 0}, {1, 0}, {1, 0}, {0, -1}}, nil, nil},
{3, 2, Point{2, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
{0, 7, Point{3, 3}, []Point{{0, 0}, {1, 0}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
{1, 7, Point{3, 3}, []Point{{0, 2}, {1, 0}, {1, 0}, {0, -1}, {0, -1}}, nil, nil},
{2, 7, Point{3, 3}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}, {1, 0}}, nil, nil},
{3, 7, Point{3, 3}, []Point{{0, 2}, {0, -1}, {0, -1}, {1, 0}, {1, 0}}, nil, nil},
{0, 3, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-2, 1}, {1, 0}}, nil, nil},
{1, 3, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {1, 0}, {0, 1}}, nil, nil},
{2, 3, Point{3, 2}, []Point{{1, 0}, {1, 0}, {-2, 1}, {1, 0}, {1, 0}}, nil, nil},
{3, 3, Point{2, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {-1, 1}, {1, 0}}, nil, nil},
{0, 4, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-1, 1}, {1, 0}}, nil, nil},
{1, 4, Point{2, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {-1, 1}, {1, 0}}, nil, nil},
{2, 4, Point{3, 2}, []Point{{0, 0}, {1, 0}, {-1, 1}, {1, 0}, {1, 0}}, nil, nil},
{3, 4, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {1, 0}, {-1, 1}}, nil, nil},
{0, 7, Point{3, 2}, []Point{{0, 0}, {2, 0}, {-2, 1}, {1, 0}, {1, 0}}, nil, nil},
{1, 7, Point{2, 3}, []Point{{0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 0}}, nil, nil},
{2, 7, Point{3, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {-2, 1}, {2, 0}}, nil, nil},
{3, 7, Point{2, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {-1, 1}, {1, 0}}, nil, nil},
{0, 5, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}, {-1, 1}}, nil, nil},
{1, 5, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{2, 5, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
{3, 5, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
{0, 6, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-2, 1}, {1, 0}, {0, 1}}, nil, nil},
{1, 6, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
{2, 6, Point{3, 3}, []Point{{1, 0}, {0, 1}, {1, 0}, {-2, 1}, {1, 0}}, nil, nil},
{3, 6, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{0, 0, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
{1, 0, Point{2, 4}, []Point{{1, 0}, {-1, 1}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
{2, 0, Point{4, 2}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{2, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}, {-1, 1}}, nil, nil},
{0, 2, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{1, 2, Point{2, 4}, []Point{{1, 0}, {0, 1}, {-1, 1}, {1, 0}, {0, 1}}, nil, nil},
{2, 2, Point{4, 2}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 2, Point{2, 4}, []Point{{0, 0}, {0, 1}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
{0, 1, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
{1, 1, Point{3, 3}, []Point{{2, 0}, {-1, 1}, {1, 0}, {-2, 1}, {1, 0}}, nil, nil},
{2, 1, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
{3, 1, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-2, 1}, {1, 0}, {-1, 1}}, nil, nil},
{0, 3, Point{3, 3}, []Point{{0, 0}, {1, 0}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
{1, 3, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
{2, 3, Point{3, 3}, []Point{{1, 0}, {0, 1}, {-1, 1}, {1, 0}, {1, 0}}, nil, nil},
{3, 3, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
{0, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{1, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{2, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{3, 4, Point{3, 3}, []Point{{1, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}}, nil, nil},
{0, 8, Point{4, 2}, []Point{{0, 0}, {1, 0}, {0, 1}, {1, 0}, {1, 0}}, nil, nil},
{1, 8, Point{2, 4}, []Point{{1, 0}, {-1, 1}, {1, 0}, {-1, 1}, {0, 1}}, nil, nil},
{2, 8, Point{4, 2}, []Point{{0, 0}, {1, 0}, {1, 0}, {0, 1}, {1, 0}}, nil, nil},
{3, 8, Point{2, 4}, []Point{{1, 0}, {0, 1}, {-1, 1}, {1, 0}, {-1, 1}}, nil, nil},
{0, 9, Point{4, 2}, []Point{{2, 0}, {1, 0}, {-3, 1}, {1, 0}, {1, 0}}, nil, nil},
{1, 9, Point{2, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {1, 0}, {0, 1}}, nil, nil},
{2, 9, Point{4, 2}, []Point{{1, 0}, {1, 0}, {1, 0}, {-3, 1}, {1, 0}}, nil, nil},
{3, 9, Point{2, 4}, []Point{{0, 0}, {0, 1}, {1, 0}, {0, 1}, {0, 1}}, nil, nil},
{0, 5, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
{1, 5, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-1, 1}, {-1, 1}, {1, 0}}, nil, nil},
{2, 5, Point{3, 3}, []Point{{0, 0}, {0, 1}, {1, 0}, {1, 0}, {0, 1}}, nil, nil},
{3, 5, Point{3, 3}, []Point{{1, 0}, {1, 0}, {-1, 1}, {-1, 1}, {1, 0}}, nil, nil},
{0, 6, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
{1, 6, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
{2, 6, Point{3, 3}, []Point{{2, 0}, {-2, 1}, {1, 0}, {1, 0}, {-2, 1}}, nil, nil},
{3, 6, Point{3, 3}, []Point{{0, 0}, {1, 0}, {0, 1}, {0, 1}, {1, 0}}, nil, nil},
}
This diff is collapsed.
To try Native Client by running 4s (tetris) or 5s or Spacewar:
1. Build the Go distribution for your native system.
2. Download the Native Client SDK and install it.
http://code.google.com/p/nativeclient-sdk/wiki/HowTo_GetStarted
* You only need to do steps 1 and 2.
3. Copy "./native_client*/toolchain/*/bin/sel_ldr"
from the Native Client distribution somewhere in your path as "nacl".
This will let you run binaries using "nacl -M 8.out".
The -M flag enables multithreaded access to the video library.
4. Build the Go distribution again, this time for Native Client:
cd $GOROOT/src
./all-nacl.bash
* If you didn't do step 3, the tests at the end will fail, but that's okay.
* If you are on a Mac, your dock will flicker as the "nacl" binary
starts and stops while the tests run. You can stop the tests at any time.
5. Run the programs by using
nacl -M $GOROOT/src/pkg/exp/4s/8.out
nacl -M $GOROOT/src/pkg/exp/4s/8.5s
nacl -M $GOROOT/src/pkg/exp/spacewar/8.out
6. If you have an old copy of the Native Client plugin, you may be
able to run the programs in your browser, by running
"godoc --http=:5103" and then visiting
* http://localhost:5103/src/pkg/exp/4s/4s.html
* http://localhost:5103/src/pkg/exp/4s/5s.html [sic]
* http://localhost:5103/src/pkg/exp/spacewar/spacewar.html
This usage is deprecated in favor of newere APIs in recent
releases of Native Client. More work will be necessary to support
interactive graphics when using those releases.
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include ../../../../Make.inc
TARG=exp/nacl/av
GOFILES=\
av.go\
event.go\
image.go\
include ../../../../Make.pkg
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Native Client audio/video
// Package av implements audio and video access for Native Client
// binaries running standalone or embedded in a web browser window.
//
// The C version of the API is documented at
// http://nativeclient.googlecode.com/svn/data/docs_tarball/nacl/googleclient/native_client/scons-out/doc/html/group__audio__video.html
package av
import (
"exp/draw"
"exp/nacl/srpc"
"log"
"os"
"syscall"
"unsafe"
)
var srpcEnabled = srpc.Enabled()
// native_client/src/trusted/service_runtime/include/sys/audio_video.h
// Subsystem values for Init.
const (
SubsystemVideo = 1 << iota
SubsystemAudio
SubsystemEmbed
)
// SubsystemRawEvents;
// Audio formats.
const (
AudioFormatStereo44K = iota
AudioFormatStereo48K
)
// A Window represents a connection to the Native Client window.
// It implements draw.Context.
type Window struct {
Embedded bool // running as part of a web page?
*Image // screen image
eventc chan interface{}
}
// *Window implements draw.Window.
var _ draw.Window = (*Window)(nil)
func (w *Window) EventChan() <-chan interface{} { return w.eventc }
func (w *Window) Close() os.Error {
// TODO(nigeltao): implement.
return nil
}
func (w *Window) Screen() draw.Image { return w.Image }
// Init initializes the Native Client subsystems specified by subsys.
// Init must be called before using any of the other functions
// in this package, and it must be called only once.
//
// If the SubsystemVideo flag is set, Init requests a window of size dx×dy.
// When embedded in a web page, the web page's window specification
// overrides the parameters to Init, so the returned Window may have
// a different size than requested.
//
// If the SubsystemAudio flag is set, Init requests a connection to the
// audio device carrying 44 kHz 16-bit stereo PCM audio samples.
func Init(subsys int, dx, dy int) (*Window, os.Error) {
xsubsys := subsys
if srpcEnabled {
waitBridge()
xsubsys &^= SubsystemVideo | SubsystemEmbed
}
if xsubsys&SubsystemEmbed != 0 {
return nil, os.NewError("not embedded")
}
w := new(Window)
err := multimediaInit(xsubsys)
if err != nil {
return nil, err
}
if subsys&SubsystemVideo != 0 {
if dx, dy, err = videoInit(dx, dy); err != nil {
return nil, err
}
w.Image = newImage(dx, dy, bridge.pixel)
w.eventc = make(chan interface{}, 64)
}
if subsys&SubsystemAudio != 0 {
var n int
if n, err = audioInit(AudioFormatStereo44K, 2048); err != nil {
return nil, err
}
println("audio", n)
}
if subsys&SubsystemVideo != 0 {
go w.readEvents()
}
return w, nil
}
func (w *Window) FlushImage() {
if w.Image == nil {
return
}
videoUpdate(w.Image.Linear)
}
func multimediaInit(subsys int) (err os.Error) {
return os.NewSyscallError("multimedia_init", syscall.MultimediaInit(subsys))
}
func videoInit(dx, dy int) (ndx, ndy int, err os.Error) {
if srpcEnabled {
bridge.share.ready = 1
return int(bridge.share.width), int(bridge.share.height), nil
}
if e := syscall.VideoInit(dx, dy); e != 0 {
return 0, 0, os.NewSyscallError("video_init", int(e))
}
return dx, dy, nil
}
func videoUpdate(data []Color) (err os.Error) {
if srpcEnabled {
bridge.flushRPC.Call("upcall", nil)
return
}
return os.NewSyscallError("video_update", syscall.VideoUpdate((*uint32)(&data[0])))
}
var noEvents = os.NewError("no events")
func videoPollEvent(ev []byte) (err os.Error) {
if srpcEnabled {
r := bridge.share.eq.ri
if r == bridge.share.eq.wi {
return noEvents
}
copy(ev, bridge.share.eq.event[r][0:])
bridge.share.eq.ri = (r + 1) % eqsize
return nil
}
return os.NewSyscallError("video_poll_event", syscall.VideoPollEvent(&ev[0]))
}
func audioInit(fmt int, want int) (got int, err os.Error) {
var x int
e := syscall.AudioInit(fmt, want, &x)
if e == 0 {
return x, nil
}
return 0, os.NewSyscallError("audio_init", e)
}
var audioSize uintptr
// AudioStream provides access to the audio device.
// Each call to AudioStream writes the given data,
// which should be a slice of 16-bit stereo PCM audio samples,
// and returns the number of samples required by the next
// call to AudioStream.
//
// To find out the initial number of samples to write, call AudioStream(nil).
//
func AudioStream(data []uint16) (nextSize int, err os.Error) {
if audioSize == 0 {
e := os.NewSyscallError("audio_stream", syscall.AudioStream(nil, &audioSize))
return int(audioSize), e
}
if data == nil {
return int(audioSize), nil
}
if uintptr(len(data))*2 != audioSize {
log.Printf("invalid audio size want %d got %d", audioSize, len(data))
}
e := os.NewSyscallError("audio_stream", syscall.AudioStream(&data[0], &audioSize))
return int(audioSize), e
}
// Synchronization structure to wait for bridge to become ready.
var bridge struct {
c chan bool
displayFd int
rpcFd int
share *videoShare
pixel []Color
client *srpc.Client
flushRPC *srpc.RPC
}
// Wait for bridge to become ready.
// When chan is first created, there is nothing in it,
// so this blocks. Once the bridge is ready, multimediaBridge.Run
// will drop a value into the channel. Then any calls
// to waitBridge will finish, taking the value out and immediately putting it back.
func waitBridge() { bridge.c <- <-bridge.c }
const eqsize = 64
// Data structure shared with host via mmap.
type videoShare struct {
revision int32 // definition below is rev 100 unless noted
mapSize int32
// event queue
eq struct {
ri uint32 // read index [0,eqsize)
wi uint32 // write index [0,eqsize)
eof int32
event [eqsize][64]byte
}
// now unused
_, _, _, _ int32
// video backing store information
width, height, _, size int32
ready int32 // rev 0x101
}
// The frame buffer data is videoShareSize bytes after
// the videoShare begins.
const videoShareSize = 16 * 1024
type multimediaBridge struct{}
// If using SRPC, the runtime will call this method to pass in two file descriptors,
// one to mmap to get the display memory, and another to use for SRPCs back
// to the main process.
func (multimediaBridge) Run(arg, ret []interface{}, size []int) srpc.Errno {
bridge.displayFd = arg[0].(int)
bridge.rpcFd = arg[1].(int)
var st syscall.Stat_t
if errno := syscall.Fstat(bridge.displayFd, &st); errno != 0 {
log.Exitf("mmbridge stat display: %s", os.Errno(errno))
}
addr, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
0,
uintptr(st.Size),
syscall.PROT_READ|syscall.PROT_WRITE,
syscall.MAP_SHARED,
uintptr(bridge.displayFd),
0)
if errno != 0 {
log.Exitf("mmap display: %s", os.Errno(errno))
}
bridge.share = (*videoShare)(unsafe.Pointer(addr))
// Overestimate frame buffer size
// (must use a compile-time constant)
// and then reslice. 256 megapixels (1 GB) should be enough.
fb := (*[256 * 1024 * 1024]Color)(unsafe.Pointer(addr + videoShareSize))
bridge.pixel = fb[0 : (st.Size-videoShareSize)/4]
// Configure RPC connection back to client.
var err os.Error
bridge.client, err = srpc.NewClient(bridge.rpcFd)
if err != nil {
log.Exitf("NewClient: %s", err)
}
bridge.flushRPC = bridge.client.NewRPC(nil)
// Notify waiters that the bridge is ready.
println("bridged", bridge.share.revision)
bridge.c <- true
return srpc.OK
}
func init() {
bridge.c = make(chan bool, 1)
if srpcEnabled {
srpc.Add("nacl_multimedia_bridge", "hh:", multimediaBridge{})
}
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// NaCl GUI events.
// Clients do not have raw access to the event stream
// (only filtered through the lens of package draw)
// but perhaps they will.
package av
import (
"encoding/binary"
"exp/draw"
"image"
"log"
"os"
"time"
)
// An eventType identifies the type of a Native Client Event.
type eventType uint8
const (
eventActive = 1 + iota
eventExpose
eventKeyDown
eventKeyUp
eventMouseMotion
eventMouseButtonDown
eventMouseButtonUp
eventQuit
eventUnsupported
)
// A key represents a key on a keyboard.
type key uint16
const (
keyUnknown = 0
keyFirst = 0
keyBackspace = 8
keyTab = 9
keyClear = 12
keyReturn = 13
keyPause = 19
keyEscape = 27
keySpace = 32
keyExclaim = 33
keyQuotedbl = 34
keyHash = 35
keyDollar = 36
keyAmpersand = 38
keyQuote = 39
keyLeftparen = 40
keyRightparen = 41
keyAsterisk = 42
keyPlus = 43
keyComma = 44
keyMinus = 45
keyPeriod = 46
keySlash = 47
key0 = 48
key1 = 49
key2 = 50
key3 = 51
key4 = 52
key5 = 53
key6 = 54
key7 = 55
key8 = 56
key9 = 57
keyColon = 58
keySemicolon = 59
keyLess = 60
keyEquals = 61
keyGreater = 62
keyQuestion = 63
keyAt = 64
keyLeftbracket = 91
keyBackslash = 92
keyRightbracket = 93
keyCaret = 94
keyUnderscore = 95
keyBackquote = 96
keyA = 97
keyB = 98
keyC = 99
keyD = 100
keyE = 101
keyF = 102
keyG = 103
keyH = 104
keyI = 105
keyJ = 106
keyK = 107
keyL = 108
keyM = 109
keyN = 110
keyO = 111
keyP = 112
keyQ = 113
keyR = 114
keyS = 115
keyT = 116
keyU = 117
keyV = 118
keyW = 119
keyX = 120
keyY = 121
keyZ = 122
keyDelete = 127
keyWorld0 = 160
keyWorld1 = 161
keyWorld2 = 162
keyWorld3 = 163
keyWorld4 = 164
keyWorld5 = 165
keyWorld6 = 166
keyWorld7 = 167
keyWorld8 = 168
keyWorld9 = 169
keyWorld10 = 170
keyWorld11 = 171
keyWorld12 = 172
keyWorld13 = 173
keyWorld14 = 174
keyWorld15 = 175
keyWorld16 = 176
keyWorld17 = 177
keyWorld18 = 178
keyWorld19 = 179
keyWorld20 = 180
keyWorld21 = 181
keyWorld22 = 182
keyWorld23 = 183
keyWorld24 = 184
keyWorld25 = 185
keyWorld26 = 186
keyWorld27 = 187
keyWorld28 = 188
keyWorld29 = 189
keyWorld30 = 190
keyWorld31 = 191
keyWorld32 = 192
keyWorld33 = 193
keyWorld34 = 194
keyWorld35 = 195
keyWorld36 = 196
keyWorld37 = 197
keyWorld38 = 198
keyWorld39 = 199
keyWorld40 = 200
keyWorld41 = 201
keyWorld42 = 202
keyWorld43 = 203
keyWorld44 = 204
keyWorld45 = 205
keyWorld46 = 206
keyWorld47 = 207
keyWorld48 = 208
keyWorld49 = 209
keyWorld50 = 210
keyWorld51 = 211
keyWorld52 = 212
keyWorld53 = 213
keyWorld54 = 214
keyWorld55 = 215
keyWorld56 = 216
keyWorld57 = 217
keyWorld58 = 218
keyWorld59 = 219
keyWorld60 = 220
keyWorld61 = 221
keyWorld62 = 222
keyWorld63 = 223
keyWorld64 = 224
keyWorld65 = 225
keyWorld66 = 226
keyWorld67 = 227
keyWorld68 = 228
keyWorld69 = 229
keyWorld70 = 230
keyWorld71 = 231
keyWorld72 = 232
keyWorld73 = 233
keyWorld74 = 234
keyWorld75 = 235
keyWorld76 = 236
keyWorld77 = 237
keyWorld78 = 238
keyWorld79 = 239
keyWorld80 = 240
keyWorld81 = 241
keyWorld82 = 242
keyWorld83 = 243
keyWorld84 = 244
keyWorld85 = 245
keyWorld86 = 246
keyWorld87 = 247
keyWorld88 = 248
keyWorld89 = 249
keyWorld90 = 250
keyWorld91 = 251
keyWorld92 = 252
keyWorld93 = 253
keyWorld94 = 254
keyWorld95 = 255
// Numeric keypad
keyKp0 = 256
keyKp1 = 257
keyKp2 = 258
keyKp3 = 259
keyKp4 = 260
keyKp5 = 261
keyKp6 = 262
keyKp7 = 263
keyKp8 = 264
keyKp9 = 265
keyKpPeriod = 266
keyKpDivide = 267
keyKpMultiply = 268
keyKpMinus = 269
keyKpPlus = 270
keyKpEnter = 271
keyKpEquals = 272
// Arrow & insert/delete pad
keyUp = 273
keyDown = 274
keyRight = 275
keyLeft = 276
keyInsert = 277
keyHome = 278
keyEnd = 279
keyPageup = 280
keyPagedown = 281
// Function keys
keyF1 = 282
keyF2 = 283
keyF3 = 284
keyF4 = 285
keyF5 = 286
keyF6 = 287
keyF7 = 288
keyF8 = 289
keyF9 = 290
keyF10 = 291
keyF11 = 292
keyF12 = 293
keyF13 = 294
keyF14 = 295
keyF15 = 296
// Modifier keys
keyNumlock = 300
keyCapslock = 301
keyScrollock = 302
keyRshift = 303
keyLshift = 304
keyRctrl = 305
keyLctrl = 306
keyRalt = 307
keyLalt = 308
keyRmeta = 309
keyLmeta = 310
keyLsuper = 311
keyRsuper = 312
keyMode = 313
keyCompose = 314
// Misc keys
keyHelp = 315
keyPrint = 316
keySysreq = 317
keyBreak = 318
keyMenu = 319
keyPower = 320
keyEuro = 321
keyUndo = 322
// Add any other keys here
keyLast
)
// A keymod is a set of bit flags
type keymod uint16
const (
keymodNone = 0x0000
keymodLshift = 0x0001
keymodRshift = 0x0002
keymodLctrl = 0x0040
keymodRctrl = 0x0080
keymodLalt = 0x0100
keymodRalt = 0x0200
keymodLmeta = 0x0400
keymodRmeta = 0x0800
keymodNum = 0x1000
keymodCaps = 0x2000
keymodMode = 0x4000
keymodReserved = 0x8000
)
const (
mouseButtonLeft = 1
mouseButtonMiddle = 2
mouseButtonRight = 3
mouseScrollUp = 4
mouseScrollDown = 5
)
const (
mouseStateLeftButtonPressed = 1
mouseStateMiddleButtonPressed = 2
mouseStateRightButtonPressed = 4
)
const (
activeMouse = 1 // mouse leaving/entering
activeInputFocus = 2 // input focus lost/restored
activeApplication = 4 // application minimized/restored
)
const maxEventBytes = 64
type activeEvent struct {
EventType eventType
Gain uint8
State uint8
}
type exposeEvent struct {
EventType eventType
}
type keyboardEvent struct {
EventType eventType
Device uint8
State uint8
Pad uint8
ScanCode uint8
Pad1 uint8
Key key
Mod keymod
Unicode uint16
}
type mouseMotionEvent struct {
EventType eventType
Device uint8
Buttons uint8
Pad uint8
X uint16
Y uint16
Xrel int16
Yrel int16
}
type mouseButtonEvent struct {
EventType eventType
Device uint8
Button uint8
State uint8
X uint16
Y uint16
}
type quitEvent struct {
EventType eventType
}
type syncEvent struct{}
type event interface{}
type reader []byte
func (r *reader) Read(p []byte) (n int, err os.Error) {
b := *r
if len(b) == 0 && len(p) > 0 {
return 0, os.EOF
}
n = copy(p, b)
*r = b[n:]
return
}
func (w *Window) readEvents() {
buf := make([]byte, maxEventBytes)
clean := false
var (
ea *activeEvent
ee *exposeEvent
ke *keyboardEvent
mme *mouseMotionEvent
mbe *mouseButtonEvent
qe *quitEvent
)
var m draw.MouseEvent
for {
if err := videoPollEvent(buf); err != nil {
if !clean {
clean = w.eventc <- draw.ConfigEvent{image.Config{ColorModel, w.Image.Bounds().Dx(), w.Image.Bounds().Dy()}}
}
time.Sleep(10e6) // 10ms
continue
}
clean = false
var e event
switch buf[0] {
default:
log.Print("unsupported event type", buf[0])
continue
case eventActive:
ea = new(activeEvent)
e = ea
case eventExpose:
ee = new(exposeEvent)
e = ee
case eventKeyDown, eventKeyUp:
ke = new(keyboardEvent)
e = ke
case eventMouseMotion:
mme = new(mouseMotionEvent)
e = mme
case eventMouseButtonDown, eventMouseButtonUp:
mbe = new(mouseButtonEvent)
e = mbe
case eventQuit:
qe = new(quitEvent)
e = qe
}
r := reader(buf)
if err := binary.Read(&r, binary.LittleEndian, e); err != nil {
log.Printf("unpacking %T event: %s", e, err)
continue
}
// log.Printf("%#v\n", e);
switch buf[0] {
case eventExpose:
w.eventc <- draw.ConfigEvent{image.Config{ColorModel, w.Image.Bounds().Dx(), w.Image.Bounds().Dy()}}
case eventKeyDown:
w.eventc <- draw.KeyEvent{int(ke.Key)}
case eventKeyUp:
w.eventc <- draw.KeyEvent{-int(ke.Key)}
case eventMouseMotion:
m.Loc.X = int(mme.X)
m.Loc.Y = int(mme.Y)
m.Buttons = int(mme.Buttons)
m.Nsec = time.Nanoseconds()
_ = w.eventc <- m
case eventMouseButtonDown:
m.Loc.X = int(mbe.X)
m.Loc.Y = int(mbe.Y)
// TODO(rsc): Remove uint cast once 8g bug is fixed.
m.Buttons |= 1 << uint(mbe.Button-1)
m.Nsec = time.Nanoseconds()
_ = w.eventc <- m
case eventMouseButtonUp:
m.Loc.X = int(mbe.X)
m.Loc.Y = int(mbe.Y)
// TODO(rsc): Remove uint cast once 8g bug is fixed.
m.Buttons &^= 1 << uint(mbe.Button-1)
m.Nsec = time.Nanoseconds()
_ = w.eventc <- m
case eventQuit:
close(w.eventc)
}
}
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package av
import (
"image"
)
// Native Client image format:
// a single linear array of 32-bit ARGB as packed uint32s.
// An Image represents a Native Client frame buffer.
// The pixels in the image can be accessed as a single
// linear slice or as a two-dimensional slice of slices.
// Image implements image.Image.
type Image struct {
Linear []Color
Pixel [][]Color
}
var _ image.Image = (*Image)(nil)
func (m *Image) ColorModel() image.ColorModel { return ColorModel }
func (m *Image) Bounds() image.Rectangle {
if len(m.Pixel) == 0 {
return image.ZR
}
return image.Rectangle{image.ZP, image.Point{len(m.Pixel[0]), len(m.Pixel)}}
}
func (m *Image) At(x, y int) image.Color { return m.Pixel[y][x] }
func (m *Image) Set(x, y int, color image.Color) {
if c, ok := color.(Color); ok {
m.Pixel[y][x] = c
return
}
m.Pixel[y][x] = makeColor(color.RGBA())
}
func newImage(dx, dy int, linear []Color) *Image {
if linear == nil {
linear = make([]Color, dx*dy)
}
pix := make([][]Color, dy)
for i := range pix {
pix[i] = linear[dx*i : dx*(i+1)]
}
return &Image{linear, pix}
}
// A Color represents a Native Client color value,
// a 32-bit R, G, B, A value packed as 0xAARRGGBB.
type Color uint32
func (p Color) RGBA() (r, g, b, a uint32) {
x := uint32(p)
a = x >> 24
a |= a << 8
r = (x >> 16) & 0xFF
r |= r << 8
g = (x >> 8) & 0xFF
g |= g << 8
b = x & 0xFF
b |= b << 8
return
}
func makeColor(r, g, b, a uint32) Color {
return Color(a>>8<<24 | r>>8<<16 | g>>8<<8 | b>>8)
}
func toColor(color image.Color) image.Color {
if c, ok := color.(Color); ok {
return c
}
return makeColor(color.RGBA())
}
// ColorModel is the color model corresponding to the Native Client Color.
var ColorModel = image.ColorModelFunc(toColor)
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include ../../../../Make.inc
TARG=exp/nacl/srpc
GOFILES=\
client.go\
msg.go\
server.go\
include ../../../../Make.pkg
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This package implements Native Client's simple RPC (SRPC).
package srpc
import (
"bytes"
"log"
"os"
"sync"
)
// A Client represents the client side of an SRPC connection.
type Client struct {
fd int // fd to server
r msgReceiver
s msgSender
service map[string]srv // services by name
out chan *msg // send to out to write to connection
mu sync.Mutex // protects pending, idGen
pending map[uint64]*RPC
idGen uint64 // generator for request IDs
}
// A srv is a single method that the server offers.
type srv struct {
num uint32 // method number
fmt string // argument format
}
// An RPC represents a single RPC issued by a client.
type RPC struct {
Ret []interface{} // Return values
Done chan *RPC // Channel where notification of done arrives
Errno Errno // Status code
c *Client
id uint64 // request id
}
// NewClient allocates a new client using the file descriptor fd.
func NewClient(fd int) (c *Client, err os.Error) {
c = new(Client)
c.fd = fd
c.r.fd = fd
c.s.fd = fd
c.service = make(map[string]srv)
c.pending = make(map[uint64]*RPC)
// service discovery request
m := &msg{
protocol: protocol,
isReq: true,
Ret: []interface{}{[]byte(nil)},
Size: []int{4000},
}
m.packRequest()
c.s.send(m)
m, err = c.r.recv()
if err != nil {
return nil, err
}
m.unpackResponse()
if m.status != OK {
log.Printf("NewClient service_discovery: %s", m.status)
return nil, m.status
}
for n, line := range bytes.Split(m.Ret[0].([]byte), []byte{'\n'}, -1) {
i := bytes.Index(line, []byte{':'})
if i < 0 {
continue
}
c.service[string(line[0:i])] = srv{uint32(n), string(line[i+1:])}
}
c.out = make(chan *msg)
go c.input()
go c.output()
return c, nil
}
func (c *Client) input() {
for {
m, err := c.r.recv()
if err != nil {
log.Exitf("client recv: %s", err)
}
if m.unpackResponse(); m.status != OK {
log.Printf("invalid message: %s", m.status)
continue
}
c.mu.Lock()
rpc, ok := c.pending[m.requestId]
if ok {
c.pending[m.requestId] = nil, false
}
c.mu.Unlock()
if !ok {
log.Print("unexpected response")
continue
}
rpc.Ret = m.Ret
rpc.Done <- rpc
}
}
func (c *Client) output() {
for m := range c.out {
c.s.send(m)
}
}
// NewRPC creates a new RPC on the client connection.
func (c *Client) NewRPC(done chan *RPC) *RPC {
if done == nil {
done = make(chan *RPC)
}
c.mu.Lock()
id := c.idGen
c.idGen++
c.mu.Unlock()
return &RPC{nil, done, OK, c, id}
}
// Start issues an RPC request for method name with the given arguments.
// The RPC r must not be in use for another pending request.
// To wait for the RPC to finish, receive from r.Done and then
// inspect r.Ret and r.Errno.
func (r *RPC) Start(name string, arg []interface{}) {
var m msg
r.Errno = OK
r.c.mu.Lock()
srv, ok := r.c.service[name]
if !ok {
r.c.mu.Unlock()
r.Errno = ErrBadRPCNumber
r.Done <- r
return
}
r.c.pending[r.id] = r
r.c.mu.Unlock()
m.protocol = protocol
m.requestId = r.id
m.isReq = true
m.rpcNumber = srv.num
m.Arg = arg
// Fill in the return values and sizes to generate
// the right type chars. We'll take most any size.
// Skip over input arguments.
// We could check them against arg, but the server
// will do that anyway.
i := 0
for srv.fmt[i] != ':' {
i++
}
fmt := srv.fmt[i+1:]
// Now the return prototypes.
m.Ret = make([]interface{}, len(fmt)-i)
m.Size = make([]int, len(fmt)-i)
for i := 0; i < len(fmt); i++ {
switch fmt[i] {
default:
log.Exitf("unexpected service type %c", fmt[i])
case 'b':
m.Ret[i] = false
case 'C':
m.Ret[i] = []byte(nil)
m.Size[i] = 1 << 30
case 'd':
m.Ret[i] = float64(0)
case 'D':
m.Ret[i] = []float64(nil)
m.Size[i] = 1 << 30
case 'h':
m.Ret[i] = int(-1)
case 'i':
m.Ret[i] = int32(0)
case 'I':
m.Ret[i] = []int32(nil)
m.Size[i] = 1 << 30
case 's':
m.Ret[i] = ""
m.Size[i] = 1 << 30
}
}
m.packRequest()
r.c.out <- &m
}
// Call is a convenient wrapper that starts the RPC request,
// waits for it to finish, and then returns the results.
// Its implementation is:
//
// r.Start(name, arg)
// <-r.Done
// return r.Ret, r.Errno
//
func (r *RPC) Call(name string, arg []interface{}) (ret []interface{}, err Errno) {
r.Start(name, arg)
<-r.Done
return r.Ret, r.Errno
}
This diff is collapsed.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// SRPC server
package srpc
import (
"bytes"
"log"
"os"
"syscall"
)
// TODO(rsc): I'd prefer to make this
// type Handler func(m *msg) Errno
// but NaCl can't use closures.
// The explicit interface is a way to attach state.
// A Handler is a handler for an SRPC method.
// It reads arguments from arg, checks size for array limits,
// writes return values to ret, and returns an Errno status code.
type Handler interface {
Run(arg, ret []interface{}, size []int) Errno
}
type method struct {
name string
fmt string
handler Handler
}
var rpcMethod []method
// BUG(rsc): Add's format string should be replaced by analyzing the
// type of an arbitrary func passed in an interface{} using reflection.
// Add registers a handler for the named method.
// Fmt is a Native Client format string, a sequence of
// alphabetic characters representing the types of the parameter values,
// a colon, and then a sequence of alphabetic characters
// representing the types of the returned values.
// The format characters and corresponding dynamic types are:
//
// b bool
// C []byte
// d float64
// D []float64
// h int // a file descriptor (aka handle)
// i int32
// I []int32
// s string
//
func Add(name, fmt string, handler Handler) {
rpcMethod = append(rpcMethod, method{name, fmt, handler})
}
// Serve accepts new SRPC connections from the file descriptor fd
// and answers RPCs issued on those connections.
// It closes fd and returns an error if the imc_accept system call fails.
func Serve(fd int) os.Error {
defer syscall.Close(fd)
for {
cfd, _, e := syscall.Syscall(syscall.SYS_IMC_ACCEPT, uintptr(fd), 0, 0)
if e != 0 {
return os.NewSyscallError("imc_accept", int(e))
}
go serveLoop(int(cfd))
}
panic("unreachable")
}
func serveLoop(fd int) {
c := make(chan *msg)
go sendLoop(fd, c)
var r msgReceiver
r.fd = fd
for {
m, err := r.recv()
if err != nil {
break
}
m.unpackRequest()
if !m.gotHeader {
log.Printf("cannot unpack header: %s", m.status)
continue
}
// log.Printf("<- %#v", m);
m.isReq = false // set up for response
go serveMsg(m, c)
}
close(c)
}
func sendLoop(fd int, c <-chan *msg) {
var s msgSender
s.fd = fd
for m := range c {
// log.Printf("-> %#v", m);
m.packResponse()
s.send(m)
}
syscall.Close(fd)
}
func serveMsg(m *msg, c chan<- *msg) {
if m.status != OK {
c <- m
return
}
if m.rpcNumber >= uint32(len(rpcMethod)) {
m.status = ErrBadRPCNumber
c <- m
return
}
meth := &rpcMethod[m.rpcNumber]
if meth.fmt != m.fmt {
switch {
case len(m.fmt) < len(meth.fmt):
m.status = ErrTooFewArgs
case len(m.fmt) > len(meth.fmt):
m.status = ErrTooManyArgs
default:
// There's a type mismatch.
// It's an in-arg mismatch if the mismatch happens
// before the colon; otherwise it's an out-arg mismatch.
m.status = ErrInArgTypeMismatch
for i := 0; i < len(m.fmt) && m.fmt[i] == meth.fmt[i]; i++ {
if m.fmt[i] == ':' {
m.status = ErrOutArgTypeMismatch
break
}
}
}
c <- m
return
}
m.status = meth.handler.Run(m.Arg, m.Ret, m.Size)
c <- m
}
// ServeRuntime serves RPCs issued by the Native Client embedded runtime.
// This should be called by main once all methods have been registered using Add.
func ServeRuntime() os.Error {
// Call getFd to check that we are running embedded.
if _, err := getFd(); err != nil {
return err
}
// We are running embedded.
// The fd returned by getFd is a red herring.
// Accept connections on magic fd 3.
return Serve(3)
}
// getFd runs the srpc_get_fd system call.
func getFd() (fd int, err os.Error) {
r1, _, e := syscall.Syscall(syscall.SYS_SRPC_GET_FD, 0, 0, 0)
return int(r1), os.NewSyscallError("srpc_get_fd", int(e))
}
// Enabled returns true if SRPC is enabled in the Native Client runtime.
func Enabled() bool {
_, err := getFd()
return err == nil
}
// Service #0, service_discovery, returns a list of the other services
// and their argument formats.
type serviceDiscovery struct{}
func (serviceDiscovery) Run(arg, ret []interface{}, size []int) Errno {
var b bytes.Buffer
for _, m := range rpcMethod {
b.WriteString(m.name)
b.WriteByte(':')
b.WriteString(m.fmt)
b.WriteByte('\n')
}
if b.Len() > size[0] {
return ErrNoMemory
}
ret[0] = b.Bytes()
return OK
}
func init() { Add("service_discovery", ":C", serviceDiscovery{}) }
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
all: 8.out
pdp1.8: pdp1.go
8g pdp1.go
spacewar.8: spacewar.go code.go pdp1.8
8g spacewar.go code.go
8.out: spacewar.8
8l spacewar.8
clean:
rm -f *.8 8.out
This diff is collapsed.
// Copyright (c) 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
// Portions Copyright (c) 2009 The Go Authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This package and spacewar.go implement a simple PDP-1 emulator
// complete enough to run the original PDP-1 video game Spacewar!
// See ../../nacl/README for details on running them.
//
// They are a translation of the Java emulator pdp1.java in
// http://spacewar.oversigma.com/sources/sources.zip.
//
// See also the PDP-1 handbook at http://www.dbit.com/~greeng3/pdp1/pdp1.html
//
// http://spacewar.oversigma.com/readme.html reads:
//
// Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell,
// and Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by
// Stephen Russell, Peter Samson, Dan Edwards, and Martin Graetz,
// together with Alan Kotok, Steve Piner, and Robert A Saunders.
// Spacewar! is in the public domain, but this credit paragraph must
// accompany all distributed versions of the program.
//
// This is the original version! Martin Graetz provided us with a
// printed version of the source. We typed in in again - it was about
// 40 pages long - and re-assembled it with a PDP-1 assembler written
// in PERL. The resulting binary runs on a PDP-1 emulator written as
// a Java applet. The code is extremely faithful to the original. There
// are only two changes. 1)The spaceships have been made bigger and
// 2) The overall timing has been special cased to deal with varying
// machine speeds.
//
// The "a", "s", "d", "f" keys control one of the spaceships. The "k",
// "l", ";", "'" keys control the other. The controls are spin one
// way, spin the other, thrust, and fire.
//
// Barry Silverman
// Brian Silverman
// Vadim Gerasimov
//
package pdp1
import (
"bufio"
"fmt"
"os"
"io"
)
type Word uint32
const mask = 0777777
const sign = 0400000
const (
_ = iota // 00
opAND
opIOR
opXOR
opXCT
_
_
opCALJDA
opLAC // 10
opLIO
opDAC
opDAP
_
opDIO
opDZM
_
opADD // 20
opSUB
opIDX
opISP
opSAD
opSAS
opMUS
opDIS
opJMP // 30
opJSP
opSKP
opSFT
opLAW
opIOT
_
opOPR
)
// A Trapper represents an object with a Trap method.
// The machine calls the Trap method to implement the
// PDP-1 IOT instruction.
type Trapper interface {
Trap(y Word)
}
// An M represents the machine state of a PDP-1.
// Clients can set Display to install an output device.
type M struct {
AC, IO, PC, OV Word
Mem [010000]Word
Flag [7]bool
Sense [7]bool
Halt bool
}
// Step runs a single machine instruction.
func (m *M) Step(t Trapper) os.Error {
inst := m.Mem[m.PC]
m.PC++
return m.run(inst, t)
}
// Normalize actual 32-bit integer i to 18-bit ones-complement integer.
// Interpret mod 0777777, because 0777777 == -0 == +0 == 0000000.
func norm(i Word) Word {
i += i >> 18
i &= mask
if i == mask {
i = 0
}
return i
}
type UnknownInstrError struct {
Inst Word
PC Word
}
func (e UnknownInstrError) String() string {
return fmt.Sprintf("unknown instruction %06o at %06o", e.Inst, e.PC)
}
type HaltError Word
func (e HaltError) String() string {
return fmt.Sprintf("executed HLT instruction at %06o", e)
}
type LoopError Word
func (e LoopError) String() string { return fmt.Sprintf("indirect load looping at %06o", e) }
func (m *M) run(inst Word, t Trapper) os.Error {
ib, y := (inst>>12)&1, inst&07777
op := inst >> 13
if op < opSKP && op != opCALJDA {
for n := 0; ib != 0; n++ {
if n > 07777 {
return LoopError(m.PC - 1)
}
ib = (m.Mem[y] >> 12) & 1
y = m.Mem[y] & 07777
}
}
switch op {
case opAND:
m.AC &= m.Mem[y]
case opIOR:
m.AC |= m.Mem[y]
case opXOR:
m.AC ^= m.Mem[y]
case opXCT:
m.run(m.Mem[y], t)
case opCALJDA:
a := y
if ib == 0 {
a = 64
}
m.Mem[a] = m.AC
m.AC = (m.OV << 17) + m.PC
m.PC = a + 1
case opLAC:
m.AC = m.Mem[y]
case opLIO:
m.IO = m.Mem[y]
case opDAC:
m.Mem[y] = m.AC
case opDAP:
m.Mem[y] = m.Mem[y]&0770000 | m.AC&07777
case opDIO:
m.Mem[y] = m.IO
case opDZM:
m.Mem[y] = 0
case opADD:
m.AC += m.Mem[y]
m.OV = m.AC >> 18
m.AC = norm(m.AC)
case opSUB:
diffSigns := (m.AC^m.Mem[y])>>17 == 1
m.AC += m.Mem[y] ^ mask
m.AC = norm(m.AC)
if diffSigns && m.Mem[y]>>17 == m.AC>>17 {
m.OV = 1
}
case opIDX:
m.AC = norm(m.Mem[y] + 1)
m.Mem[y] = m.AC
case opISP:
m.AC = norm(m.Mem[y] + 1)
m.Mem[y] = m.AC
if m.AC&sign == 0 {
m.PC++
}
case opSAD:
if m.AC != m.Mem[y] {
m.PC++
}
case opSAS:
if m.AC == m.Mem[y] {
m.PC++
}
case opMUS:
if m.IO&1 == 1 {
m.AC += m.Mem[y]
m.AC = norm(m.AC)
}
m.IO = (m.IO>>1 | m.AC<<17) & mask
m.AC >>= 1
case opDIS:
m.AC, m.IO = (m.AC<<1|m.IO>>17)&mask,
((m.IO<<1|m.AC>>17)&mask)^1
if m.IO&1 == 1 {
m.AC = m.AC + (m.Mem[y] ^ mask)
} else {
m.AC = m.AC + 1 + m.Mem[y]
}
m.AC = norm(m.AC)
case opJMP:
m.PC = y
case opJSP:
m.AC = (m.OV << 17) + m.PC
m.PC = y
case opSKP:
cond := y&0100 == 0100 && m.AC == 0 ||
y&0200 == 0200 && m.AC>>17 == 0 ||
y&0400 == 0400 && m.AC>>17 == 1 ||
y&01000 == 01000 && m.OV == 0 ||
y&02000 == 02000 && m.IO>>17 == 0 ||
y&7 != 0 && !m.Flag[y&7] ||
y&070 != 0 && !m.Sense[(y&070)>>3] ||
y&070 == 010
if (ib == 0) == cond {
m.PC++
}
if y&01000 == 01000 {
m.OV = 0
}
case opSFT:
for count := inst & 0777; count != 0; count >>= 1 {
if count&1 == 0 {
continue
}
switch (inst >> 9) & 017 {
case 001: // rotate AC left
m.AC = (m.AC<<1 | m.AC>>17) & mask
case 002: // rotate IO left
m.IO = (m.IO<<1 | m.IO>>17) & mask
case 003: // rotate AC and IO left.
w := uint64(m.AC)<<18 | uint64(m.IO)
w = w<<1 | w>>35
m.AC = Word(w>>18) & mask
m.IO = Word(w) & mask
case 005: // shift AC left (excluding sign bit)
m.AC = (m.AC<<1|m.AC>>17)&mask&^sign | m.AC&sign
case 006: // shift IO left (excluding sign bit)
m.IO = (m.IO<<1|m.IO>>17)&mask&^sign | m.IO&sign
case 007: // shift AC and IO left (excluding AC's sign bit)
w := uint64(m.AC)<<18 | uint64(m.IO)
w = w<<1 | w>>35
m.AC = Word(w>>18)&mask&^sign | m.AC&sign
m.IO = Word(w)&mask&^sign | m.AC&sign
case 011: // rotate AC right
m.AC = (m.AC>>1 | m.AC<<17) & mask
case 012: // rotate IO right
m.IO = (m.IO>>1 | m.IO<<17) & mask
case 013: // rotate AC and IO right
w := uint64(m.AC)<<18 | uint64(m.IO)
w = w>>1 | w<<35
m.AC = Word(w>>18) & mask
m.IO = Word(w) & mask
case 015: // shift AC right (excluding sign bit)
m.AC = m.AC>>1 | m.AC&sign
case 016: // shift IO right (excluding sign bit)
m.IO = m.IO>>1 | m.IO&sign
case 017: // shift AC and IO right (excluding AC's sign bit)
w := uint64(m.AC)<<18 | uint64(m.IO)
w = w >> 1
m.AC = Word(w>>18) | m.AC&sign
m.IO = Word(w) & mask
default:
goto Unknown
}
}
case opLAW:
if ib == 0 {
m.AC = y
} else {
m.AC = y ^ mask
}
case opIOT:
t.Trap(y)
case opOPR:
if y&0200 == 0200 {
m.AC = 0
}
if y&04000 == 04000 {
m.IO = 0
}
if y&01000 == 01000 {
m.AC ^= mask
}
if y&0400 == 0400 {
m.PC--
return HaltError(m.PC)
}
switch i, f := y&7, y&010 == 010; {
case i == 7:
for i := 2; i < 7; i++ {
m.Flag[i] = f
}
case i >= 2:
m.Flag[i] = f
}
default:
Unknown:
return UnknownInstrError{inst, m.PC - 1}
}
return nil
}
// Load loads the machine's memory from a text input file
// listing octal address-value pairs, one per line, matching the
// regular expression ^[ +]([0-7]+)\t([0-7]+).
func (m *M) Load(r io.Reader) os.Error {
b := bufio.NewReader(r)
for {
line, err := b.ReadString('\n')
if err != nil {
if err != os.EOF {
return err
}
break
}
// look for ^[ +]([0-9]+)\t([0-9]+)
if line[0] != ' ' && line[0] != '+' {
continue
}
i := 1
a := Word(0)
for ; i < len(line) && '0' <= line[i] && line[i] <= '7'; i++ {
a = a*8 + Word(line[i]-'0')
}
if i >= len(line) || line[i] != '\t' || i == 1 {
continue
}
v := Word(0)
j := i
for i++; i < len(line) && '0' <= line[i] && line[i] <= '7'; i++ {
v = v*8 + Word(line[i]-'0')
}
if i == j {
continue
}
m.Mem[a] = v
}
return nil
}
// Copyright (c) 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
// Portions Copyright (c) 2009 The Go Authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// See ../../nacl/README.
package main
import (
"bytes"
"exp/draw"
"exp/nacl/av"
"exp/nacl/srpc"
"image"
"log"
"os"
"runtime"
"time"
"./pdp1"
)
func main() {
runtime.LockOSThread()
if srpc.Enabled() {
go srpc.ServeRuntime()
}
w, err := av.Init(av.SubsystemVideo, 512, 512)
if err != nil {
log.Exitf("av.Init: %s", err)
}
kc := make(chan int)
go demuxEvents(w, kc)
var m SpacewarPDP1
m.Init(w, kc)
m.PC = 4
f := bytes.NewBuffer([]byte(spacewarCode))
if err = m.Load(f); err != nil {
log.Exitf("loading %s: %s", "spacewar.lst", err)
}
for err == nil {
//fmt.Printf("step PC=%06o ", m.PC);
//fmt.Printf("inst=%06o AC=%06o IO=%06o OV=%o\n",
// m.Mem[m.PC], m.AC, m.IO, m.OV);
err = m.Step()
}
log.Exitf("step: %s", err)
}
func demuxEvents(w draw.Window, kc chan int) {
for event := range w.EventChan() {
switch e := event.(type) {
case draw.KeyEvent:
kc <- e.Key
}
}
os.Exit(0)
}
// A SpacewarPDP1 is a PDP-1 machine configured to run Spacewar!
// It responds to traps by drawing on the display, and it flushes the
// display and pauses every second time the program counter reaches
// instruction 02051.
type SpacewarPDP1 struct {
pdp1.M
nframe int
frameTime int64
ctxt draw.Window
dx, dy int
screen draw.Image
ctl pdp1.Word
kc <-chan int
colorModel image.ColorModel
cmap []image.Color
pix [][]uint8
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func (m *SpacewarPDP1) Init(ctxt draw.Window, kc chan int) {
m.ctxt = ctxt
m.kc = kc
m.screen = ctxt.Screen()
m.dx = m.screen.Bounds().Dx()
m.dy = m.screen.Bounds().Dy()
m.colorModel = m.screen.ColorModel()
m.pix = make([][]uint8, m.dy)
for i := range m.pix {
m.pix[i] = make([]uint8, m.dx)
}
m.cmap = make([]image.Color, 256)
for i := range m.cmap {
var r, g, b uint8
r = uint8(min(0, 255))
g = uint8(min(i*2, 255))
b = uint8(min(0, 255))
m.cmap[i] = m.colorModel.Convert(image.RGBAColor{r, g, b, 0xff})
}
}
const (
frameDelay = 56 * 1e6 // 56 ms
)
var ctlBits = [...]pdp1.Word{
'f': 0000001,
'd': 0000002,
'a': 0000004,
's': 0000010,
'\'': 0040000,
';': 0100000,
'k': 0200000,
'l': 0400000,
}
func (m *SpacewarPDP1) Step() os.Error {
if m.PC == 02051 {
m.pollInput()
m.nframe++
if m.nframe&1 == 0 {
m.flush()
t := time.Nanoseconds()
if t >= m.frameTime+3*frameDelay {
m.frameTime = t
} else {
m.frameTime += frameDelay
for t < m.frameTime {
time.Sleep(m.frameTime - t)
t = time.Nanoseconds()
}
}
}
}
return m.M.Step(m)
}
func (m *SpacewarPDP1) Trap(y pdp1.Word) {
switch y & 077 {
case 7:
x := int(m.AC+0400000) & 0777777
y := int(m.IO+0400000) & 0777777
x = x * m.dx / 0777777
y = y * m.dy / 0777777
if 0 <= x && x < m.dx && 0 <= y && y < m.dy {
n := uint8(min(int(m.pix[y][x])+128, 255))
m.pix[y][x] = n
}
case 011:
m.IO = m.ctl
}
}
func (m *SpacewarPDP1) flush() {
// Update screen image; simulate phosphor decay.
for y := 0; y < m.dy; y++ {
for x := 0; x < m.dx; x++ {
m.screen.Set(x, y, m.cmap[m.pix[y][x]])
m.pix[y][x] >>= 1
}
}
m.ctxt.FlushImage()
}
func (m *SpacewarPDP1) pollInput() {
for {
select {
case ch := <-m.kc:
if 0 <= ch && ch < len(ctlBits) {
m.ctl |= ctlBits[ch]
}
if 0 <= -ch && -ch < len(ctlBits) {
m.ctl &^= ctlBits[-ch]
}
default:
return
}
}
}
<h1>Spacewar</h1>
<table>
<tr><td valign=top>
<embed name="nacl_module" id="pluginobj" src="8.out" type="application/x-nacl-srpc" width=512 height=512>
<td valign=top>
This is a Go translation of the Java emulator pdp1.java in
<a href="http://spacewar.oversigma.com/sources/sources.zip">http://spacewar.oversigma.com/sources/sources.zip</a>.
See <a href="pdp1.go">pdp1.go</a>, <a href="spacewar.go">spacewar.go</a>,
and
<a href="http://spacewar.oversigma.com/readme.html">http://spacewar.oversigma.com/readme.html</a>.
<br><br>
The <i>a</i>, <i>s</i>, <i>d</i>, <i>f</i> keys control one of the spaceships. The <i>k</i>,
<i>l</i>, <i>;</i>, <i>'</i> keys control the other. The controls are spin one
way, spin the other, thrust, and fire.
<br>
<br>
<b>You may need to click on the game window to
focus the keyboard on it.</b>
</table>
......@@ -41,13 +41,6 @@ GOFILES_linux=\
dnsconfig.go\
dnsclient.go\
port.go\
GOFILES_nacl=\
newpollserver.go\
fd.go\
dnsconfig.go\
dnsclient.go\
port.go\
GOFILES_windows=\
resolv_windows.go\
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
import (
"os"
"syscall"
)
type pollster struct{}
func newpollster() (p *pollster, err os.Error) {
return nil, os.NewSyscallError("networking", syscall.ENACL)
}
func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
_, err := newpollster()
return err
}
func (p *pollster) StopWaiting(fd int, bits uint) {
}
func (p *pollster) DelFD(fd int, mode int) {}
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
_, err = newpollster()
return
}
func (p *pollster) Close() os.Error { return nil }
......@@ -33,11 +33,6 @@ GOFILES_linux=\
file_unix.go\
sys_linux.go\
GOFILES_nacl=\
env_unix.go\
file_unix.go\
sys_nacl.go\
GOFILES_windows=\
env_windows.go\
file_windows.go\
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
import (
"syscall"
"unsafe"
)
const (
blockSize = 4096 // TODO(r): use statfs
)
func clen(n []byte) int {
for i := 0; i < len(n); i++ {
if n[i] == 0 {
return i
}
}
return len(n)
}
func (file *File) Readdirnames(count int) (names []string, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = new(dirInfo)
// The buffer must be at least a block long.
// TODO(r): use fstatfs to find fs block size.
file.dirinfo.buf = make([]byte, blockSize)
}
d := file.dirinfo
size := count
if size < 0 {
size = 100
}
names = make([]string, 0, size) // Empty with room to grow.
for count != 0 {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
var errno int
d.nbuf, errno = syscall.Getdents(file.fd, d.buf)
if errno != 0 {
return names, NewSyscallError("getdents", errno)
}
if d.nbuf <= 0 {
break // EOF
}
d.bufp = 0
}
// Drain the buffer
for count != 0 && d.bufp < d.nbuf {
dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp]))
d.bufp += int(dirent.Reclen)
if dirent.Ino == 0 { // File absent in directory.
continue
}
bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:clen(bytes[0:])])
if name == "." || name == ".." { // Useless names
continue
}
count--
names = append(names, name)
}
}
return names, nil
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
import "syscall"
func isSymlink(stat *syscall.Stat_t) bool {
return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
}
func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
fi.Dev = uint64(stat.Dev)
fi.Ino = uint64(stat.Ino)
fi.Nlink = uint64(stat.Nlink)
fi.Mode = stat.Mode
fi.Uid = int(stat.Uid)
fi.Gid = int(stat.Gid)
fi.Rdev = uint64(stat.Rdev)
fi.Size = int64(stat.Size)
fi.Blksize = int64(stat.Blksize)
fi.Blocks = int64(stat.Blocks)
fi.Atime_ns = int64(stat.Atime) * 1e9
fi.Mtime_ns = int64(stat.Mtime) * 1e9
fi.Ctime_ns = int64(stat.Ctime) * 1e9
for i := len(name) - 1; i >= 0; i-- {
if name[i] == '/' {
name = name[i+1:]
break
}
}
fi.Name = name
if isSymlink(lstat) && !isSymlink(stat) {
fi.FollowedSymlink = true
}
return fi
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
func Hostname() (name string, err Error) { return "nacl", nil }
......@@ -18,9 +18,6 @@ GOFILES_darwin=\
GOFILES_linux=\
path_unix.go
GOFILES_nacl=\
path_unix.go
GOFILES_windows=\
path_windows.go
......
......@@ -15,9 +15,6 @@ runtime·closure(int32 siz, byte *fn, byte *arg0)
int32 i, n;
int32 pcrel;
if(runtime·goos != nil && runtime·strcmp((uint8*)runtime·goos, (uint8*)"nacl") == 0)
runtime·throw("no closures in native client yet");
if(siz < 0 || siz%4 != 0)
runtime·throw("bad closure size");
......
......@@ -165,9 +165,3 @@ ifeq ($(GOARCH),386)
traceback.$O: amd64/traceback.c
$(CC) $(CFLAGS) $<
endif
# NaCl closure is special.
ifeq ($(GOOS),nacl)
closure.$O: nacl/$(GOARCH)/closure.c
$(CC) $(CFLAGS) $<
endif
......@@ -327,10 +327,6 @@ struct MHeap
byte *min;
byte *max;
// range of addresses we might see in a Native Client closure
byte *closure_min;
byte *closure_max;
// central free lists for small size classes.
// the union makes sure that the MCentrals are
// spaced 64 bytes apart, so that each MCentral.Lock
......
......@@ -76,22 +76,6 @@ scanblock(byte *b, int64 n)
obj = vp[i];
if(obj == nil)
continue;
if(runtime·mheap.closure_min != nil && runtime·mheap.closure_min <= (byte*)obj && (byte*)obj < runtime·mheap.closure_max) {
if((((uintptr)obj) & 63) != 0)
continue;
// Looks like a Native Client closure.
// Actual pointer is pointed at by address in first instruction.
// Embedded pointer starts at byte 2.
// If it is f4f4f4f4 then that space hasn't been
// used for a closure yet (f4 is the HLT instruction).
// See nacl/386/closure.c for more.
void **pp;
pp = *(void***)((byte*)obj+2);
if(pp == (void**)0xf4f4f4f4) // HLT... - not a closure after all
continue;
obj = *pp;
}
if(runtime·mheap.min <= (byte*)obj && (byte*)obj < runtime·mheap.max) {
if(runtime·mlookup(obj, &obj, &size, nil, &refp)) {
ref = *refp;
......
......@@ -165,7 +165,7 @@ MHeap_Grow(MHeap *h, uintptr npage)
// Ask for a big chunk, to reduce the number of mappings
// the operating system needs to track; also amortizes
// the overhead of an operating system mapping.
// For Native Client, allocate a multiple of 64kB (16 pages).
// Allocate a multiple of 64kB (16 pages).
npage = (npage+15)&~15;
ask = npage<<PageShift;
if(ask < HeapAllocChunk)
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* Closure implementation for Native Client.
* Native Client imposes some interesting restrictions.
*
* First, we can only add new code to the code segment
* through a special system call, and we have to pick the
* maximum amount of code we're going to add that way
* at link time (8l reserves 512 kB for us).
*
* Second, once we've added the code we can't ever
* change it or delete it. If we want to garbage collect
* the memory and then reuse it for another closure,
* we have to do so without editing the code.
*
* To address both of these, we fill the code segment pieces
* with very stylized closures. Each has the form given below
* in the comments on the closasm array, with ** replaced by
* a pointer to a single word of memory. The garbage collector
* treats a pointer to such a closure as equivalent to the value
* held in **. This tiled run of closures is called the closure array.
*
* The ptr points at a ClosureData structure, defined below,
* which gives the function, arguments, and size for the
* closuretramp function. The ClosureData structure has
* in it a pointer to a ClosureFreeList structure holding the index
* of the closure in the closure array (but not a pointer to it).
* That structure has a finalizer: when the garbage collector
* notices that the ClosureFreeList structure is not referenced
* anymore, that means the closure is not referenced, so it
* can be reused. To do that, the ClosureFreeList entry is put
* onto an actual free list.
*/
#include "runtime.h"
#include "malloc.h"
// NaCl system call to copy data into text segment.
extern int32 runtime·dyncode_copy(void*, void*, int32);
enum{
// Allocate chunks of 4096 bytes worth of closures:
// at 64 bytes each, that's 64 closures.
ClosureChunk = 4096,
ClosureSize = 64,
};
typedef struct ClosureFreeList ClosureFreeList;
struct ClosureFreeList
{
ClosureFreeList *next;
int32 index; // into closure array
};
// Known to closasm
typedef struct ClosureData ClosureData;
struct ClosureData
{
ClosureFreeList *free;
byte *fn;
int32 siz;
// then args
};
// List of the closure data pointer blocks we've allocated
// and hard-coded in the closure text segments.
// The list keeps the pointer blocks from getting collected.
typedef struct ClosureDataList ClosureDataList;
struct ClosureDataList
{
ClosureData **block;
ClosureDataList *next;
};
static struct {
Lock;
byte *code;
byte *ecode;
ClosureFreeList *free;
ClosureDataList *datalist;
byte buf[ClosureChunk];
} clos;
static byte closasm[64] = {
0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
0x8b, 0x4b, 8, // MOVL 8(BX), CX
0x8d, 0x73, 12, // LEAL 12(BX), SI
0x29, 0xcc, // SUBL CX, SP
0x89, 0xe7, // MOVL SP, DI
0xc1, 0xe9, 2, // SHRL $2, CX
0xf3, 0xa5, // REP MOVSL
0x8b, 0x5b, 4, // MOVL 4(BX), BX
0x90, 0x90, 0x90, // NOP...
0x83, 0xe3, ~31, // ANDL $~31, BX
0xff, 0xd3, // CALL *BX
// --- 32-byte boundary
0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
0x03, 0x63, 8, // ADDL 8(BX), SP
0x5b, // POPL BX
0x83, 0xe3, ~31, // ANDL $~31, BX
0xff, 0xe3, // JMP *BX
0xf4, // HLT...
0xf4, 0xf4, 0xf4, 0xf4,
0xf4, 0xf4, 0xf4, 0xf4,
0xf4, 0xf4, 0xf4, 0xf4,
0xf4, 0xf4, 0xf4, 0xf4,
// --- 32-byte boundary
};
// Returns immediate pointer from closure code block.
// Triple pointer:
// p is the instruction stream
// p+2 is the location of the immediate value
// *(p+2) is the immediate value, a word in the pointer block
// permanently associated with this closure.
// **(p+2) is the ClosureData* pointer temporarily associated
// with this closure.
//
#define codeptr(p) *(ClosureData***)((byte*)(p)+2)
void
runtime·finclosure(void *v)
{
byte *p;
ClosureFreeList *f;
f = v;
p = clos.code + f->index*ClosureSize;
*codeptr(p) = nil;
runtime·lock(&clos);
f->next = clos.free;
clos.free = f;
runtime·unlock(&clos);
}
#pragma textflag 7
// func closure(siz int32,
// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
void
runtime·closure(int32 siz, byte *fn, byte *arg0)
{
byte *p, **ret;
int32 e, i, n, off;
extern byte rodata[], etext[];
ClosureData *d, **block;
ClosureDataList *l;
ClosureFreeList *f;
if(siz < 0 || siz%4 != 0)
runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(rsc): implement stack growth preamble?
runtime·throw("closure too big");
}
runtime·lock(&clos);
if(clos.free == nil) {
// Allocate more closures.
if(clos.code == nil) {
// First time: find closure space, between end of text
// segment and beginning of data.
clos.code = (byte*)(((uintptr)etext + 65535) & ~65535);
clos.ecode = clos.code;
runtime·mheap.closure_min = clos.code;
runtime·mheap.closure_max = rodata;
}
if(clos.ecode+ClosureChunk > rodata) {
// Last ditch effort: garbage collect and hope.
runtime·unlock(&clos);
runtime·gc(1);
runtime·lock(&clos);
if(clos.free != nil)
goto alloc;
runtime·throw("ran out of room for closures in text segment");
}
n = ClosureChunk/ClosureSize;
// Allocate the pointer block as opaque to the
// garbage collector. Finalizers will clean up.
block = runtime·mallocgc(n*sizeof block[0], RefNoPointers, 1, 1);
// Pointers into the pointer block are getting added
// to the text segment; keep a pointer here in the data
// segment so that the garbage collector doesn't free
// the block itself.
l = runtime·mal(sizeof *l);
l->block = block;
l->next = clos.datalist;
clos.datalist = l;
p = clos.buf;
off = (clos.ecode - clos.code)/ClosureSize;
for(i=0; i<n; i++) {
f = runtime·mal(sizeof *f);
f->index = off++;
f->next = clos.free;
clos.free = f;
// There are two hard-coded immediate values in
// the assembly that need to be pp+i, one 2 bytes in
// and one 2 bytes after the 32-byte boundary.
runtime·mcpy(p, closasm, ClosureSize);
*(ClosureData***)(p+2) = block+i;
*(ClosureData***)(p+32+2) = block+i;
p += ClosureSize;
}
if(p != clos.buf+sizeof clos.buf)
runtime·throw("bad buf math in closure");
e = runtime·dyncode_copy(clos.ecode, clos.buf, ClosureChunk);
if(e != 0) {
runtime·fd = 2;
if(e == -22)
runtime·throw("NaCl running with dyncode_copy disabled; export NACLDYNCODE=1 in your environment");
runtime·printf("dyncode_copy: error %d\n", e);
runtime·throw("dyncode_copy");
}
clos.ecode += ClosureChunk;
}
alloc:
// Grab a free closure and save the data pointer in its indirect pointer.
f = clos.free;
clos.free = f->next;
f->next = nil;
p = clos.code + f->index*ClosureSize;
d = runtime·mal(sizeof(*d)+siz);
d->free = f;
d->fn = fn;
d->siz = siz;
runtime·mcpy((byte*)(d+1), (byte*)&arg0, siz);
*codeptr(p) = d;
runtime·addfinalizer(f, runtime·finclosure, 0);
runtime·unlock(&clos);
*ret = p;
}
// godefs -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client defs.c
// MACHINE GENERATED - DO NOT EDIT.
// Constants
enum {
PROT_NONE = 0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
};
// Types
#pragma pack on
#pragma pack off
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Native Client and Linux use the same linkage to main
TEXT _rt0_386_nacl(SB),7,$0
JMP _rt0_386(SB)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
#include "defs.h"
#include "signals.h"
#include "os.h"
void
runtime·initsig(int32 queue)
{
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// System calls and other sys.stuff for 386, Linux
//
#include "386/asm.h"
// http://code.google.com/p/nativeclient/source/browse/trunk/src/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h
#define SYS_exit 30
#define SYS_mmap 21
#define SYS_munmap 22
#define SYS_thread_create 80
#define SYS_thread_exit 81
#define SYS_tls_init 82
#define SYS_write 13
#define SYS_close 11
#define SYS_mutex_create 70
#define SYS_mutex_lock 71
#define SYS_mutex_unlock 73
#define SYS_gettimeofday 40
#define SYS_dyncode_copy 104
#define SYSCALL(x) $(0x10000+SYS_/**/x * 32)
TEXT runtime·exit(SB),7,$4
MOVL code+0(FP), AX
MOVL AX, 0(SP)
CALL SYSCALL(exit)
INT $3 // not reached
RET
TEXT runtime·exit1(SB),7,$4
MOVL code+0(FP), AX
MOVL AX, 0(SP)
CALL SYSCALL(thread_exit)
INT $3 // not reached
RET
TEXT runtime·write(SB),7,$0
JMP SYSCALL(write)
TEXT runtime·close(SB),7,$0
JMP SYSCALL(close)
TEXT runtime·mutex_create(SB),7,$0
JMP SYSCALL(mutex_create)
TEXT runtime·mutex_lock(SB),7,$0
JMP SYSCALL(mutex_lock)
TEXT runtime·mutex_unlock(SB),7,$0
JMP SYSCALL(mutex_unlock)
TEXT runtime·thread_create(SB),7,$0
JMP SYSCALL(thread_create)
TEXT runtime·dyncode_copy(SB),7,$0
JMP SYSCALL(dyncode_copy)
// For Native Client: a simple no-op function.
// Inserting a call to this no-op is a simple way
// to trigger an alignment.
TEXT runtime·naclnop(SB),7,$0
RET
TEXT runtime·mmap(SB),7,$24
MOVL a1+0(FP), BX
MOVL a2+4(FP), CX // round up to 64 kB boundary; silences nacl warning
ADDL $(64*1024-1), CX
ANDL $~(64*1024-1), CX
MOVL a3+8(FP), DX
MOVL a4+12(FP), SI
MOVL a5+16(FP), DI
MOVL a6+20(FP), BP
MOVL BX, 0(SP)
MOVL CX, 4(SP)
MOVL DX, 8(SP)
MOVL SI, 12(SP)
MOVL DI, 16(SP)
MOVL BP, 20(SP)
CALL SYSCALL(mmap)
CMPL AX, $0xfffff001
JLS 6(PC)
MOVL $1, 0(SP)
MOVL $runtime·mmap_failed(SB), 4(SP)
MOVL $12, 8(SP) // "mmap failed\n"
CALL SYSCALL(write)
INT $3
RET
TEXT runtime·munmap(SB),7,$0
JMP SYSCALL(munmap)
TEXT runtime·gettime(SB),7,$32
LEAL 8(SP), BX
MOVL BX, 0(SP)
MOVL $0, 4(SP)
CALL SYSCALL(gettimeofday)
MOVL 8(SP), BX // sec
MOVL sec+0(FP), DI
MOVL BX, (DI)
MOVL $0, 4(DI) // zero extend 32 -> 64 bits
MOVL 12(SP), BX // usec
MOVL usec+4(FP), DI
MOVL BX, (DI)
RET
// setldt(int entry, int address, int limit)
TEXT runtime·setldt(SB),7,$32
// entry is ignored - nacl tells us the
// segment selector to use and stores it in GS.
MOVL address+4(FP), BX
MOVL limit+8(FP), CX
MOVL BX, 0(SP)
MOVL CX, 4(SP)
CALL SYSCALL(tls_init)
CMPL AX, $0xfffff001
JLS 6(PC)
MOVL $1, 0(SP)
MOVL $runtime·tls_init_failed(SB), 4(SP)
MOVL $16, 8(SP) // "tls_init failed\n"
CALL SYSCALL(write)
INT $3
RET
// There's no good way (yet?) to get stack traces out of a
// broken NaCl process, so if something goes wrong,
// print an error string before dying.
DATA runtime·mmap_failed(SB)/8, $"mmap fai"
DATA mmap_failed+8(SB)/4, $"led\n"
GLOBL runtime·mmap_failed(SB), $12
DATA runtime·tls_init_failed(SB)/8, $"tls_init"
DATA tls_init_failed+8(SB)/8, $" failed\n"
GLOBL runtime·tls_init_failed(SB), $16
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Input to godefs.
godefs -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client defs.c >386/defs.h
*/
#define __native_client__ 1
#define suseconds_t nacl_suseconds_t_1
#include <sys/types.h>
#undef suseconds_t
#include <sys/mman.h>
enum {
$PROT_NONE = PROT_NONE,
$PROT_READ = PROT_READ,
$PROT_WRITE = PROT_WRITE,
$PROT_EXEC = PROT_EXEC,
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
};
#include "runtime.h"
#include "defs.h"
#include "os.h"
#include "malloc.h"
enum {
NaclPage = 0x10000
};
void*
runtime·SysAlloc(uintptr n)
{
mstats.sys += n;
return runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
}
void
runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
// TODO(rsc): call madvise MADV_DONTNEED
}
void
runtime·SysFree(void *v, uintptr n)
{
// round to page size or else nacl prints annoying log messages
mstats.sys -= n;
n = (n+NaclPage-1) & ~(NaclPage-1);
runtime·munmap(v, n);
}
void
runtime·SysMemInit(void)
{
}
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
int32 runtime·thread_create(void(*fn)(void), void *stk, void *tls, int32 tlssize);
void runtime·close(int32);
int32 runtime·mutex_create(void);
int32 runtime·mutex_lock(int32);
int32 runtime·mutex_unlock(int32);
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// OS-Specific Go definitions of internal structures. Master is runtime.h
package runtime
type lock struct {
key uint32
sema uint32
}
type note lock
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "runtime.h"
#include "defs.h"
#include "os.h"
int8 *goos = "nacl";
// Thread-safe allocation of a mutex.
// (The name sema is left over from the Darwin implementation.
// Native Client implements semaphores too, but it is just a shim
// over the host implementation, which on some hosts imposes a very
// low limit on how many semaphores can be created.)
//
// Psema points at a mutex descriptor.
// It starts out zero, meaning no mutex.
// Fill it in, being careful of others calling initsema
// simultaneously.
static void
initsema(uint32 *psema)
{
uint32 sema;
if(*psema != 0) // already have one
return;
sema = runtime·mutex_create();
if((int32)sema < 0) {
runtime·printf("mutex_create failed\n");
runtime·breakpoint();
}
// mutex_create returns a file descriptor;
// shift it up and add the 1 bit so that can
// distinguish unintialized from fd 0.
sema = (sema<<1) | 1;
if(!cas(psema, 0, sema)){
// Someone else filled it in. Use theirs.
runtime·close(sema);
return;
}
}
// Lock and unlock.
// Defer entirely to Native Client.
// The expense of a call into Native Client is more like
// a function call than a system call, so as long as the
// Native Client lock implementation is good, we can't
// do better ourselves.
static void
xlock(int32 fd)
{
if(mutex_lock(fd) < 0) {
runtime·printf("mutex_lock failed\n");
runtime·breakpoint();
}
}
static void
xunlock(int32 fd)
{
if(mutex_unlock(fd) < 0) {
runtime·printf("mutex_lock failed\n");
runtime·breakpoint();
}
}
void
runtime·lock(Lock *l)
{
if(m->locks < 0)
runtime·throw("lock count");
m->locks++;
if(l->sema == 0)
runtime·initsema(&l->sema);
runtime·xlock(l->sema>>1);
}
void
runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
runtime·throw("lock count");
runtime·xunlock(l->sema>>1);
}
void
runtime·destroylock(Lock*)
{
}
// One-time notifications.
//
// Since the lock/unlock implementation already
// takes care of sleeping in the kernel, we just reuse it.
// (But it's a weird use, so it gets its own interface.)
//
// We use a lock to represent the event:
// unlocked == event has happened.
// Thus the lock starts out locked, and to wait for the
// event you try to lock the lock. To signal the event,
// you unlock the lock.
//
// Native Client does not require that the thread acquiring
// a lock be the thread that releases the lock, so this is safe.
void
runtime·noteclear(Note *n)
{
if(n->lock.sema == 0)
runtime·initsema(&n->lock.sema);
runtime·xlock(n->lock.sema>>1);
}
void
runtime·notewakeup(Note *n)
{
if(n->lock.sema == 0) {
runtime·printf("notewakeup without noteclear");
runtime·breakpoint();
}
runtime·xunlock(n->lock.sema>>1);
}
void
runtime·notesleep(Note *n)
{
if(n->lock.sema == 0) {
runtime·printf("notesleep without noteclear");
runtime·breakpoint();
}
runtime·xlock(n->lock.sema>>1);
runtime·xunlock(n->lock.sema>>1); // Let other sleepers find out too.
}
void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
void **vstk;
// I wish every OS made thread creation this easy.
m->tls[0] = (uint32)g;
m->tls[1] = (uint32)m;
vstk = stk;
*--vstk = nil;
if(thread_create(fn, vstk, m->tls, sizeof m->tls) < 0) {
runtime·printf("thread_create failed\n");
runtime·breakpoint();
}
}
void
runtime·osinit(void)
{
}
// Called to initialize a new m (including the bootstrap m).
void
runtime·minit(void)
{
}
......@@ -30,10 +30,6 @@ GOFILES_linux=\
syscall_unix.go\
exec_unix.go\
GOFILES_nacl=\
syscall_unix.go\
exec_unix.go\
GOFILES_windows=\
exec_windows.go
......
This diff is collapsed.
#!/bin/sh
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Generate Go code listing error values (ENAMETOOLONG etc)
# for Native Client.
echo '// mkerrors_nacl.sh' "$@"
echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo
echo 'package syscall'
echo
echo 'const ('
perl -n -e '
if(/#define\s+NACL_ABI_(\S*)\s+([0-9]+)/) {
print "\t$1 = $2;\n"
}
' $1
echo ' ENACL = 99; /* otherwise unused */'
echo ')'
echo
echo
echo '// Error table'
echo 'var errors = [...]string {'
perl -n -e '
if(/#define\s+NACL_ABI_(\S*)\s+([0-9]+)\s+\/\* (.*) \*\//) {
$err = $1;
$text = $3;
if($text =~ /^[A-Z][a-z]/) {
# lowercase first letter: Bad -> bad, but STREAM -> STREAM.
$l = substr($text, 0, 1);
$rest = substr($text, 1);
$l =~ y/A-Z/a-z/;
$text = $l . $rest;
}
print "\t$err: \"$text\",\n";
}
' $1
echo ' ENACL: "not supported by native client",'
echo '}'
This diff is collapsed.
This diff is collapsed.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package syscall
func Getpagesize() int { return 4096 }
func NsecToTimeval(nsec int64) (tv Timeval) {
tv.Sec = int32(nsec / 1e9)
tv.Usec = int32(nsec % 1e9 / 1e3)
return
}
func NsecToTimespec(nsec int64) (ts Timespec) {
ts.Sec = int32(nsec / 1e9)
ts.Nsec = int32(nsec % 1e9)
return
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment