Giter Site home page Giter Site logo

c-octo's Introduction

C-Octo

Octode Demo

This project is a rewrite of the web-based Octo CHIP-8 development toolkit in C. This port can run on a wide variety of older or lower-powered devices which would struggle with a modern web browser. C-Octo also provides an enhanced CLI and offline experience for those who prefer to use an external text editor.

The C-Octo suite includes octo-cli, a command-line compiler, octo-run, a minimal runtime and debugger that can be executed from the command-line, octo-de, a self-contained "Fantasy Console"-style programming environment, and several reusable libraries. Why not give Octo a spin on the PocketCHIP gathering dust in your closet?

Project Structure

C-Octo is split into several files by function:

  • octo_compiler.h: a freestanding compiler for Octo Assembly Language.
  • octo_emulator.h: a CHIP-8, SCHIP, and XO-CHIP compatible emulator core which performs no IO.
  • octo_cartridge.h: routines for reading and producing "Octocarts", which encode both an Octo program and configuration metadata into a GIF image.
  • octo_util.h: assorted support routines shared by octo_run.c and octo_de.c.
  • octo_cli.c: a minimal interface for the Octo compiler which depends only upon the C standard library and <sys/stat.h>.
  • octo_run.c: a minimal graphical frontend for the Octo emulator and compiler which depends on SDL2.
  • octo_de.c: a richer graphical frontend including a text editor, sprite editor, and other conveniences.

Installation

To build from source you will need a C compiler and (probably) SDL2. The provided Makefile will build everything, attempt to copy binaries to /usr/local/bin/, and create a configuration .octo.rc file in your home directory.

For detailed information about building and installing on different platforms, see the Build Guide.

Octo-CLI

$octo-cli
usage: ./octo-cli <source> [<destination>] [-s <symfile>]

The source file may be a .8o source file or a .gif octocart. If the destination has a .ch8 extension, a CHIP-8 binary will be produced. If the destination has a .gif extension, an octocart will be produced. If the destination has a .8o extension, the source text of an input octocart will be extracted. If no destination is specified, the resultant .ch8 binary will be piped to stdout.

if the -s flag is provided, the compiler will write out a CSV file containing all the symbols defined in the input program: breakpoints, constants (including labels), aliases, and monitors, for use with external debugging tools. For example:

$ cat symdemo.8o
:monitor v6 8
: main
	:alias acc v2
	acc += 1
	:breakpoint "wait, then go"
	acc := 0

$ octo-cli symdemo.8o temp.ch8 -s syms.csv && cat syms.csv
type,name,value
breakpoint,"wait, then go",514
constant,main,512
alias,unpack-hi,0
alias,unpack-lo,1
alias,acc,2
monitor,v6,8

The make testcli target will run a series of integration tests for this tool.

Octo-Run

$octo-run
octo-run v1.0
usage: ./octo-run <source> [-c <path>]
where <source> is a .ch8 or .8o

Octo-run will execute a .ch8 binary or compile and run an Octo program. While executing, the same basic debugging features are available as in web-octo: i toggles a user interrupt and the display of the register file, o single-steps while interrupted, and m toggles the display of memory monitors, if any are registered. Command-F or Ctrl-F toggle fullscreen mode and Escape or backtick quit.

If provided, the -c flag may be used to indicate a configuration file which should override the global .octo.rc file. This makes it easier to configure colors, speed, and other options for an individual program while working on multiple projects.

If a gamepad is detected, axes will be mapped to mirror A,S,W, and D on the keyboard and buttons will similarly be mapped to E and Q.

Octode

$octo-de

Octode includes a text editor, sprite editor, palette editor, and a runtime/debugger identical to octo-run. With the exception of the sprite editor, the user interface can be controlled entirely via the keyboard, and should work equally well with a mouse or touchscreen. For detailed information about Octode, see the Octode User Guide.

Configuration File

Octo-run and Octode look for a file named .octo.rc in the user's home directory. If present, it can be used to configure a variety of useful settings for the tools. The file has a traditional .INI structure- empty lines or lines beginning with # are ignored, and anything else consists of a key and value separated by =. Meaningful keys are as follows:

  • ui.windowed: if 1, the tool runs in a window. If 0, it will attempt to run in fullscreen.

  • ui.software_render: if 1, prefer a software renderer over hardware-acceleration. On some low-power devices, "accelerated" mode is unusably slow!

  • ui.win_scale: if greater than 1, scale up the "logical" window dimensions by an integer factor.

  • ui.win_width: horizontal size in pixels when in windowed mode.

  • ui.win_height: vertical size in pixels when in windowed mode.

  • ui.volume: volume of XO-CHIP sound (0-127). A value of 0 will disable audio entirely.

  • core.tickrate: number of CHIP-8 instructions to execute per 60hz frame.

  • core.max_rom: the maximum number of bytes the compiler will permit when assembling a ROM.

  • core.rotation: one of {0, 90, 180, 270} to rotate the CHIP-8 display. Does not impact the rest of the UI.

  • core.font: one of {octo, vip, dream_6800, eti_660, schip, fish} to select the built-in CHIP-8 font.

  • color.plane0, color.plane1, color.plane2, color.plane3: colors for the 4 XO-CHIP "plane" colors.

  • color.background: the border drawn behind the CHIP-8 display when no sound is being played.

  • color.sound: the alternate border color when sound is being played.

  • quirks.shift: if 1, vx <<= vy and vx >>= vy modify vx in place and ignore vy, like SCHIP.

  • quirks.loadstore: if 1, load and store do not post-increment i, like SCHIP.

  • quirks.jump0: if 1, emulate a buggy behavior of SCHIP on the HP-48: the 4 high bits of the target address of jump0 determines the offset register used (instead of always v0).

  • quirks.logic: if 1, clear vf after &=,|= and ^=. On the VIP, these instructions leave vf in an unknown state.

  • quirks.clip: if 1, do not "wrap" sprite drawing around the edges of the display.

  • quirks.vblank: if 1, drawing a sprite will block until the end of the 60hz frame, like the VIP.

All colors are specified as 6-digit RGB in hexadecimal, like 996600. The default quirks settings, palette, and other options correspond to those of web-octo.

c-octo's People

Contributors

effix avatar ephphatha avatar johnearnest avatar pushfoo avatar tobiasvl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

c-octo's Issues

Malformed text mode definitions crash instead of displaying a syntax error

Expected behavior

When confronted with an absent bracket definition for a string mode, the original js-based Octo outputs a helpful syntax error message. For the example code below, Octo produces this message: line 7: Expected '{' for definition of string mode 'text'..

: font-5x3
    0x60 0xA0 0xA0 0xA0 0xC0

# omitted brackets containing index calculation 
:stringmode text "0"

: main
	vF := key
	jump main

Current behavior

Both octo-de and octo-run crash on the example code above, printing Killed in the terminal on a new line instead of a syntax error:

$ octo-run bad_stringmode_def.8o
Killed
$

octo-de also hangs for a moment before crashing.

Persistent user flags

It'd be neat if C-Octo had consistent user flags, like Octo does. Perhaps they could be stored in .octo.rc – that way it's possible to keep separate user flags for each game too, by using the -c option.

License File

I see the web Octo IDE is under the MIT license. A license file for C-Octo would clarify the correct license and usage.

A few errors whilist building

`src/octo_de.c: In function ‘render_text_editor’:
src/octo_de.c:517:69: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size between 230 and 250 [-Werror=format-truncation=]
517 | snprintf(state.text_status,sizeof(state.text_status),"(%d:%d) %s",prog->error_line+1,prog->error_pos+1,prog->error);state.text_err=1;
| ^~
src/octo_de.c:517:7: note: ‘snprintf’ output between 7 and 4122 bytes into a destination of size 256
517 | snprintf(state.text_status,sizeof(state.text_status),"(%d:%d) %s",prog->error_line+1,prog->error_pos+1,prog->error);state.text_err=1;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:689:65: error: ‘%s’ directive output may be truncated writing up to 255 bytes into a region of size 250 [-Werror=format-truncation=]
689 | snprintf(state.text_status,sizeof(state.text_status),"Find: %s",trimmed); state.text_err=0;
| ^~ ~~~~~~~
src/octo_de.c:689:5: note: ‘snprintf’ output between 7 and 262 bytes into a destination of size 256
689 | snprintf(state.text_status,sizeof(state.text_status),"Find: %s",trimmed); state.text_err=0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c: In function ‘open_choose’:
src/octo_de.c:1307:83: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 232 [-Werror=format-truncation=]
1307 | snprintf(state.text_status,sizeof(state.text_status),"Imported CHIP-8 binary '%s'",entry->name);state.text_err=0;
| ^~
src/octo_de.c:1307:5: note: ‘snprintf’ output between 26 and 4121 bytes into a destination of size 256
1307 | snprintf(state.text_status,sizeof(state.text_status),"Imported CHIP-8 binary '%s'",entry->name);state.text_err=0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:1287:106: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 235 [-Werror=format-truncation=]
1287 | if(stat(filename,&st)!=0){snprintf(state.text_status,sizeof(state.text_status),"Unable to open file '%s'",entry->name);state.text_err=1;return;}
| ^~

src/octo_de.c:1287:31: note: ‘snprintf’ output between 23 and 4118 bytes into a destination of size 256
1287 | if(stat(filename,&st)!=0){snprintf(state.text_status,sizeof(state.text_status),"Unable to open file '%s'",entry->name);state.text_err=1;return;}
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:1323:72: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 243 [-Werror=format-truncation=]
1323 | snprintf(state.text_status,sizeof(state.text_status),"Opened file '%s'",entry->name);state.text_err=0;
| ^~
src/octo_de.c:1323:5: note: ‘snprintf’ output between 15 and 4110 bytes into a destination of size 256
1323 | snprintf(state.text_status,sizeof(state.text_status),"Opened file '%s'",entry->name);state.text_err=0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:1312:106: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 235 [-Werror=format-truncation=]
1312 | if(stat(filename,&st)!=0){snprintf(state.text_status,sizeof(state.text_status),"Unable to open file '%s'",entry->name);state.text_err=1;return;}
| ^~

src/octo_de.c:1312:31: note: ‘snprintf’ output between 23 and 4118 bytes into a destination of size 256
1312 | if(stat(filename,&st)!=0){snprintf(state.text_status,sizeof(state.text_status),"Unable to open file '%s'",entry->name);state.text_err=1;return;}
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:1337:76: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 239 [-Werror=format-truncation=]
1337 | snprintf(state.text_status,sizeof(state.text_status),"Opened octocart '%s'",entry->name);state.text_err=0;
| ^~
src/octo_de.c:1337:5: note: ‘snprintf’ output between 19 and 4114 bytes into a destination of size 256
1337 | snprintf(state.text_status,sizeof(state.text_status),"Opened octocart '%s'",entry->name);state.text_err=0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:1329:86: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 231 [-Werror=format-truncation=]
1329 | snprintf(state.text_status,sizeof(state.text_status),"Unable to read octocart '%s'",entry->name);state.text_err=1;
| ^~
src/octo_de.c:1329:7: note: ‘snprintf’ output between 27 and 4122 bytes into a destination of size 256
1329 | snprintf(state.text_status,sizeof(state.text_status),"Unable to read octocart '%s'",entry->name);state.text_err=1;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c: In function ‘save_file’:
src/octo_de.c:1375:73: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 240 [-Werror=format-truncation=]
1375 | snprintf(state.text_status,sizeof(state.text_status),"Saved octocart '%s'",state.open_name);state.text_err=0;
| ^~ ~~~~~~~~~~~~~~~
src/octo_de.c:1375:3: note: ‘snprintf’ output between 18 and 4113 bytes into a destination of size 256
1375 | snprintf(state.text_status,sizeof(state.text_status),"Saved octocart '%s'",state.open_name);state.text_err=0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/octo_de.c:1367:85: error: ‘%s’ directive output may be truncated writing up to 4095 bytes into a region of size 230 [-Werror=format-truncation=]
1367 | snprintf(state.text_status,sizeof(state.text_status),"Unable to write octocart '%s'",state.open_name);state.text_err=1;
| ^~ ~~~~~~~~~~~~~~~
src/octo_de.c:1367:5: note: ‘snprintf’ output between 28 and 4123 bytes into a destination of size 256
1367 | snprintf(state.text_status,sizeof(state.text_status),"Unable to write octocart '%s'",state.open_name);state.text_err=1;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [Makefile:42: ide] Error 1`
Removing -Werror from the makefile fixed it for me. A temporary fix that is.

Bug: Key waiting state blocks hiding monitors

I'll make a PR soon. ada0845

Affected

octo-run, octo-de

Steps to replicate

  1. Run code below
:monitor v0 4

: main
  i := circle
  plane 1
  loop
    sprite v0 v1 8
    v0 += 3
    v1 += 5
    v2 := key
  again

: circle
 0x3C 0x7E 0xFF 0xFF 0xFF 0xFF 0x7E 0x3C
  1. press m to engage monitor
  2. press m to disengage monitor

Expected behavior

Monitors turn off

Actual Behavior

Monitors don't turn off

Random instruction always generates identical PRNG return values

Random instructions generate the same series of values each run. This affects both octo-run and octo-de. Web-based Octo does not do this.

I'll be submitting a PR with a quick fix calling srand with the time as a seed, but it might be worthwhile to allow setting custom seeds as a runtime option to help debugging.

code to replicate

This generates the same value each time it is run.

: main
	:breakpoint example
	v0 := random 0xFF
	v1 := 1
;

error: a function declaration without a prototype is deprecated in all versions of C

When compiling on macOS 13.5 (Ventura) with clang, the compiler is not happy:

[ 16%] Building C object CMakeFiles/octo-cli.dir/src/octo_cli.c.o
In file included from /Users/cas/src/c-octo/src/octo_cli.c:10:
/Users/cas/src/c-octo/src/octo_compiler.h:178:28: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes]
octo_macro* octo_make_macro()               {octo_macro*r=calloc(1,sizeof(octo_macro));octo_list_init(&r->args),octo_list_init(&r->body);return r;}
                           ^
                            void
/Users/cas/src/c-octo/src/octo_compiler.h:179:28: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes]
octo_smode* octo_make_smode()               {octo_smode*r=calloc(1,sizeof(octo_smode));                                                  return r;}
                           ^
                            void
/Users/cas/src/c-octo/src/octo_compiler.h:181:28: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes]
octo_mon  * octo_make_mon  ()               {octo_mon  *r=calloc(1,sizeof(octo_mon  ));                                                  return r;}
                           ^
                            void
3 errors generated.
make[2]: *** [CMakeFiles/octo-cli.dir/src/octo_cli.c.o] Error 1
make[1]: *** [CMakeFiles/octo-cli.dir/all] Error 2
make: *** [all] Error 2

Information on the compiler:

% clang --version
Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.