Permalink
Browse files

Added dcpu-list and -deps commands. Removed 'dcpu' command.

It was too much of a hassle to be worth it.

Applied numerous bug fixes and amended documentation.
  • Loading branch information...
1 parent 9fb37ce commit de6bbe077b12af00a0fdbe7cf1499010eea98f3e @jteeuwen committed Nov 16, 2012
View
35 ENV.md
@@ -0,0 +1,35 @@
+## Environment variables
+
+Bfore using any of the DCPU tools in this project, we must set the `$DCPUROOT`
+environment variable to a path where all our DCPU code will live. For example:
+
+ export DCPUROOT=$HOME/dcpu
+
+The `$DCPUROOT` environment variable is used to find package sources and
+resolve dependencies. It lists the directory location where all the DCPU tools
+should look for source code and compiled package archives.
+
+The path specified by `$DCPUROOT` must have a prescribed structure:
+
+ * The `src/` directory holds source code for all packages and programs.
+ * The `pkg/` directory holds assembled package archives. These can be imported
+ into other DCPU programs/packages.
+ * The `bin/` directory holds the final, linked executable programs, which can
+ be run on the emulator.
+
+Here is an example of the expected directory layout:
+
+ $HOME/dcpu/
+ src/
+ foo/
+ bar/ (DASM source for package 'bar')
+ x.dasm
+ quux/ (DASM source for package 'quux')
+ y.dasm
+ pkg/
+ foo/
+ bar.a (Installed package archive)
+ bin/
+ foo/
+ quux.bin (Installed executable)
+
View
@@ -0,0 +1,38 @@
+## Package/import paths
+
+All DCPU command line tools operate on a set of package paths:
+
+ dcpu-xxx [options] <packages>
+
+Usually, `<packages>` is a list of one or more import paths. An import path
+that is a rooted path or that begins with a `.` or `..` element is interpreted
+as a file system path and denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in the directory
+`$DCPUROOT/src/P`.
+
+If no import paths are given, the action applies to the package in the
+current directory.
+
+The special import path `all` applies to any and all packages found under
+`$DCPUROOT`. For instance: `dcpu-list all` will list all known packages on the
+local system.
+
+An import path is a pattern if it has a `/...` wildcard suffix. It can match
+any string, including the empty string. Such a pattern expands to all package
+directories found in `$DCPUROOT` trees with names matching the given pattern.
+For example: `x/...` matches package `x` as well as all of x's sub directories.
+
+Every package in a program must have a unique import path. By convention, this
+is arranged by starting each path with a unique prefix that belongs to you.
+This can be a company name, your own name, or anything else you prefer.
+This is done to prevent name collisions with packages released by others.
+
+Whether an import path refers to its src, pkg or bin equivalent, depends on
+the context in which it is used. The assembler, linker and emulator will all
+have different requirements in that regard. For example, the import path
+`test/hw` can refer to one of the following components:
+
+* `$DCPUROOT/src/test/hw/*.dasm`: Source code for package 'test/hw'
+* `$DCPUROOT/pkg/test/hw.a`: Compiled archive for package 'test/hw'
+* `$DCPUROOT/bin/test/hw.bin`: Compiled executable for package 'test/hw'
View
@@ -0,0 +1,7 @@
+// This file is subject to a 1-clause BSD license.
+// Its contents can be found in the enclosed LICENSE file.
+
+// This program is a command line front end for the `asm` package.
+// It assembles DCPU assembly source into package archives.
+package main
+
View
@@ -78,6 +78,8 @@ which source code has changed since the last time the package was built.
Compiled packages are stored in $DCPUROOT/pkg/<importpath>
+[OPTIONS]
+
-f <flag-1,flag-2,...,flag-N>
A comma-separated list of flag names. These determine how the assembler
handles and generates certain parts of the code. Supported flags are:
View
@@ -0,0 +1,27 @@
+## DCPU dependencies
+
+Deps displays all dependencies for the given packages. This includes all
+dependencies for the entire dependency tree. The list generated here will tell
+us exactly which packages will be included in a final executable.
+
+The first listed entry is the target package itself, followed by an inset list
+of its dependencies. For example:
+
+ $ dcpu-deps test/deps/...
+ test/deps/a
+ test/deps/b
+ test/deps/c
+ test/deps/b
+ test/deps/c
+ test/deps/a
+ test/deps/c
+ test/deps/a
+ test/deps/b
+
+
+### License
+
+DCPU, 0x10c and related materials are Copyright 2012 Mojang.
+
+Unless otherwise stated, all of the work in this project is subject to a
+1-clause BSD license. Its contents can be found in the enclosed LICENSE file.
File renamed without changes.
View
@@ -0,0 +1,7 @@
+// This file is subject to a 1-clause BSD license.
+// Its contents can be found in the enclosed LICENSE file.
+
+// This command displays all dependencies for the given packages. This includes
+// all dependencies for the entire dependency tree. The list generated here will
+// tell us exactly which packages will be included in a final executable.
+package main
View
@@ -0,0 +1,93 @@
+// This file is subject to a 1-clause BSD license.
+// Its contents can be found in the enclosed LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "github.com/jteeuwen/dcpu/path"
+ "os"
+)
+
+func main() {
+ targets := parseArgs()
+
+ for _, targ := range targets {
+ list := path.Expand(targ)
+ if len(list) == 0 {
+ continue
+ }
+
+ for _, imp := range list {
+ var list []string
+
+ if !findDeps(imp, &list) {
+ continue
+ }
+
+ // First entry is target package itself.
+ list = list[1:]
+
+ fmt.Fprintln(os.Stdout, imp)
+ for _, dep := range list {
+ fmt.Fprintln(os.Stdout, " "+dep)
+ }
+ }
+ }
+}
+
+func parseArgs() []string {
+ flag.Usage = usage
+ version := flag.Bool("version", false, "")
+
+ flag.Parse()
+
+ if *version {
+ fmt.Printf("%s\n", Version())
+ os.Exit(0)
+ }
+
+ if flag.NArg() == 0 {
+ fmt.Fprintf(os.Stderr, "Missing link targets.\n")
+ os.Exit(1)
+ }
+
+ targets := path.Expand(flag.Arg(0))
+
+ if len(targets) == 0 {
+ fmt.Fprintf(os.Stderr, "Missing link targets.\n")
+ os.Exit(1)
+ }
+
+ return targets
+}
+
+func usage() {
+ fmt.Printf(`Usage: dcpu-deps [options] <packages>
+
+deps displays all dependencies for the given packages. This includes all
+dependencies for the entire dependency tree. The list generated here will tell
+us exactly which packages will be included in a final executable.
+
+The first listed entry is the target package itself, followed by an inset list
+of its dependencies. For example:
+
+ $ dcpu-deps test/deps/...
+ test/deps/a
+ test/deps/b
+ test/deps/c
+ test/deps/b
+ test/deps/c
+ test/deps/a
+ test/deps/c
+ test/deps/a
+ test/deps/b
+
+[OPTIONS]
+
+ -version
+ Display version information.
+
+`)
+}
@@ -9,7 +9,7 @@ import (
)
const (
- AppName = "dcpu"
+ AppName = "dcpu-deps"
AppVersionMajor = 0
AppVersionMinor = 1
)
View
@@ -3,7 +3,8 @@
**Note**: This is work in progress and should not be considered useful yet.
This is an experimental, standalone, graphical emulator for the DCPU.
-It includes fully implemented DCPU hardware.
+It includes fully implemented DCPU hardware and doubles as a code profiler
+and debugger.
### Keyboard shortcuts
View
@@ -0,0 +1,7 @@
+// This file is subject to a 1-clause BSD license.
+// Its contents can be found in the enclosed LICENSE file.
+
+// This command is a standalone, graphical emulator for the DCPU.
+// It includes fully implemented DCPU hardware and doubles as a code profiler
+// and debugger.
+package main
View
@@ -147,6 +147,8 @@ func usage() {
dcpu-emu is a graphical emulator which doubles as a code profiler and debugger.
It has all known DCPU hardware attached to it and ready for use.
+[OPTIONS]
+
-disp="lem1802"
Name of the hardware to display.
Supported hardware includes: "lem1802", "sped3".
View
@@ -0,0 +1,134 @@
+// This file is subject to a 1-clause BSD license.
+// Its contents can be found in the enclosed LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "github.com/jteeuwen/dcpu/archive"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// saveCode save the archive to disk.
+func saveCode(ar *archive.Archive, file string) error {
+ // Ensure the target directory exists.
+ dir, _ := filepath.Split(file)
+ err := os.MkdirAll(dir, 0700)
+ if err != nil {
+ return err
+ }
+
+ // Create the file.
+ fd, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+
+ defer fd.Close()
+
+ return ar.Write(fd)
+}
+
+// createHeader creates the program header.
+// Which entails the following:
+//
+// jsr $entrypoint
+// sub pc, 1
+//
+// The size of which depends on the size of the entrypoint value.
+// It will be either 2 or 3 words.
+func createHeader(entrypoint uint16) []uint16 {
+ entrypoint += 2
+
+ if entrypoint == 0xffff || entrypoint <= 0x1e {
+ return []uint16{
+ 0x00 | (0x01 << 5) | ((entrypoint + 0x21) << 10), // jsr $entrypoint
+ 0x03 | (0x1c << 5) | (0x22 << 10), // sub pc, 1
+ }
+ }
+
+ return []uint16{
+ 0x00 | (0x01 << 5) | (0x1f << 10), // jsr $entrypoint
+ entrypoint + 1,
+ 0x03 | (0x1c << 5) | (0x22 << 10), // sub pc, 1
+ }
+}
+
+// buildCode combines all archive code into a single chunk.
+func buildCode(list []*Archive, program []uint16) *archive.Archive {
+ ar := new(archive.Archive)
+ ar.Code = program
+ ar.Debug = make([]*archive.Debug, len(ar.Code))
+
+ for i := range ar.Code {
+ ar.Debug[i] = &archive.Debug{0xffff, 0, 0, 0}
+ }
+
+ for _, a := range list {
+ // Correct file name indices.
+ fc := uint16(len(ar.Files))
+
+ for _, d := range a.ar.Debug {
+ d.File += fc
+ }
+
+ // Append file names, debug symbols and code to the new archive.
+ ar.Files = append(ar.Files, a.ar.Files...)
+ ar.Debug = append(ar.Debug, a.ar.Debug...)
+ ar.Code = append(ar.Code, a.ar.Code...)
+ }
+
+ return ar
+}
+
+// findEntrypoint finds the archive defining our program entry point.
+// It also ensures we have one, and only one of these.
+// The prerequisite is that the package has one exported function or
+// label named 'Main'.
+func findEntrypoint(list []*Archive) (*Archive, uint16, error) {
+ var main []*Archive
+ var addr uint16
+
+ for _, a := range list {
+ for _, sym := range a.ar.Symbols {
+ if sym.Name == "Main" && (sym.Type == archive.SymFunction || sym.Type == archive.SymLabel) {
+ main = append(main, a)
+ addr = sym.Address
+ break
+ }
+ }
+ }
+
+ switch len(main) {
+ case 1: // pass
+ case 0:
+ return nil, 0, fmt.Errorf("No entry point found.")
+ default:
+ return nil, 0, fmt.Errorf("Too many entry points defined; Main found in: %s", nameList(main))
+ }
+
+ return main[0], addr, nil
+}
+
+// nameList returns a list of package names.
+func nameList(list []*Archive) string {
+ names := make([]string, len(list))
+
+ for i, a := range list {
+ names[i] = a.ar.Package
+ }
+
+ return strings.Join(names, ", ")
+}
+
+// findSymbol returns a symbol for the given name.
+func findSymbol(a *Archive, name string) *archive.Symbol {
+ for _, sym := range a.ar.Symbols {
+ if sym.Name == name {
+ return sym
+ }
+ }
+ return nil
+}
Oops, something went wrong.

0 comments on commit de6bbe0

Please sign in to comment.