-
-
Notifications
You must be signed in to change notification settings - Fork 489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add C template #1981
Merged
Merged
Add C template #1981
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
41affce
Add C template
Gota7 2d641d0
Remove TIC C functions
Gota7 f1338bd
Add note about memset & memcpy
Gota7 0b87d62
Add C template Makefile
Gota7 256211f
Update templates/c/README.md
Gota7 e56351d
Header Fixes
Gota7 a5e4eba
Fix Indent
Gota7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# C Starter Project Template | ||
|
||
## Pre-requisites | ||
|
||
- [WASI SDK](https://github.com/WebAssembly/wasi-sdk) | ||
|
||
## Files in this template | ||
|
||
- ```buildcart.sh``` - convenience script to build and run the game cartridge | ||
- ```buildwasm.sh``` - convenience script to build and run the Wasm program | ||
- ```Makefile``` - convenience Makefile that builds the project | ||
- ```wasmdemo.wasmp``` - TIC-80 Wasm 'script' file. Note the embedded game assets data at the end of the file. | ||
|
||
## Building your game | ||
|
||
Define the environment variable WASI_SDK_PATH; e.g., if you installed WASI | ||
into ```$HOME/wasi-sdk```, then ```export WASI_SDK_PATH=$HOME/wasi-sdk```. | ||
|
||
Edit ```src/main.c``` to implement your game. You are of course free to | ||
organize your code in more than one C source file. | ||
|
||
If you create sprites, map, music, etc., for your game, remember to | ||
replace the game asset data at the end of ```wasmdemo.wasmp``` with | ||
your creations. | ||
|
||
To build the Wasm file, execute ```make```. This generates ```cart.wasm``` | ||
in the build directory. To run: | ||
|
||
``` | ||
% tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary cart.wasm & run & exit' | ||
``` | ||
|
||
The script ```buildwasm.sh``` contains above steps as a convenience. | ||
|
||
To build a TIC-80 cartridge, first build the Wasm file, then build the | ||
cartridge file: | ||
|
||
``` | ||
% tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary cart.wasm & save game.tic & exit' | ||
``` | ||
|
||
You can then run your cartridge as follows: | ||
|
||
``` | ||
% tic80 --fs . --cmd 'load game.tic & run & exit' | ||
``` | ||
|
||
The script ```buildcart.sh``` does the above steps as a convenience. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/bin/sh | ||
rm -f game.tic | ||
make clean | ||
make | ||
tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary build/cart.wasm & save game.tic & exit' | ||
tic80 --fs . --cmd 'load game.tic & run & exit' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/bin/sh | ||
make clean | ||
make | ||
tic80 --fs . --cmd 'load wasmdemo.wasmp & import binary build/cart.wasm & run & exit' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include "tic80.h" | ||
|
||
#define max(a, b) (a > b) ? a : b | ||
#define min(a, b) (a < b) ? a : b | ||
|
||
// From WASI libc: | ||
WASM_IMPORT("snprintf") | ||
int snprintf(char* s, size_t n, const char* format, ...); | ||
|
||
int t, x, y; | ||
const char* m = "HELLO WORLD FROM C!"; | ||
int r = 0; | ||
MouseData md; | ||
uint8_t transcolors = { 14 }; | ||
|
||
WASM_EXPORT("BOOT") | ||
void BOOT() { | ||
t = 1; | ||
x = 96; | ||
y = 24; | ||
} | ||
|
||
WASM_EXPORT("TIC") | ||
void TIC() { | ||
cls(13); | ||
|
||
// The standard demo. | ||
if (btn(0) > 0) { y--; } | ||
if (btn(1) > 0) { y++; } | ||
if (btn(2) > 0) { x--; } | ||
if (btn(3) > 0) { x++; } | ||
|
||
spr(1+t%60/30*2, x, y, &transcolors, 1, 3, 0, 0, 2, 2); | ||
print(m, 60, 84, 15, 1, 1, 0); | ||
t++; | ||
|
||
// Mouse example demonstrating use of libc function. | ||
mouse(&md); | ||
if (md.left) { r = r + 2; } | ||
r--; | ||
r = max(0, min(32, r)); | ||
line(md.x, 0, md.x, 136, 11); | ||
line(0, md.y, 240, md.y, 11); | ||
circ(md.x, md.y, r, 11); | ||
|
||
const int BUFSIZ = 10; | ||
char buf[BUFSIZ]; | ||
snprintf(buf, BUFSIZ, "(%03d,%03d)", md.x, md.y); | ||
print(buf, 3, 3, 15, 0, 1, 1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#pragma once | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
#define WASM_EXPORT(name) __attribute__((export_name(name))) | ||
#define WASM_IMPORT(name) __attribute__((import_name(name))) | ||
|
||
typedef struct { | ||
uint8_t SCREEN[16320]; | ||
uint8_t PALETTE[48]; | ||
uint8_t PALETTE_MAP[8]; | ||
uint8_t BORDER_COLOR; | ||
uint8_t SCREEN_OFFSET_X; | ||
uint8_t SCREEN_OFFSET_Y; | ||
uint8_t MOUSE_CURSOR; | ||
uint8_t BLIT_SEGMENT; | ||
uint8_t RESERVED[3]; | ||
} VRAM; | ||
|
||
typedef struct { | ||
short x; short y; | ||
char scrollx; char scrolly; | ||
bool left; bool middle; bool right; | ||
} MouseData; | ||
|
||
const int32_t WIDTH = 240; | ||
const int32_t HEIGHT = 136; | ||
|
||
// Constants. | ||
const uint32_t TILES_SIZE = 8192; | ||
const uint32_t SPRITES_SIZE = 8192; | ||
const uint32_t MAP_SIZE = 32640; | ||
const uint32_t GAMEPADS_SIZE = 4; | ||
const uint32_t MOUSE_SIZE = 4; | ||
const uint32_t KEYBOARD_SIZE = 4; | ||
const uint32_t SFX_STATE_SIZE = 16; | ||
const uint32_t SOUND_REGISTERS_SIZE = 72; | ||
const uint32_t WAVEFORMS_SIZE = 256; | ||
const uint32_t SFX_SIZE = 4224; | ||
const uint32_t MUSIC_PATTERNS_SIZE = 11520; | ||
const uint32_t MUSIC_TRACKS_SIZE = 408; | ||
const uint32_t SOUND_STATE_SIZE = 4; | ||
const uint32_t STEREO_VOLUME_SIZE = 4; | ||
const uint32_t PERSISTENT_MEMORY_SIZE = 1024; | ||
const uint32_t SPRITE_FLAGS_SIZE = 512; | ||
const uint32_t SYSTEM_FONT_SIZE = 2048; | ||
const uint32_t WASM_FREE_RAM_SIZE = 163840; // 160kb | ||
|
||
// Pointers. | ||
VRAM* FRAMEBUFFER = (VRAM*)0; | ||
uint8_t* TILES = (uint8_t*)0x04000; | ||
uint8_t* SPRITES = (uint8_t*)0x06000; | ||
uint8_t* MAP = (uint8_t*)0x08000; | ||
uint8_t* GAMEPADS = (uint8_t*)0x0FF80; | ||
uint8_t* MOUSE = (uint8_t*)0x0FF84; | ||
uint8_t* KEYBOARD = (uint8_t*)0x0FF88; | ||
uint8_t* SFX_STATE = (uint8_t*)0x0FF8C; | ||
uint8_t* SOUND_REGISTERS = (uint8_t*)0x0FF9C; | ||
uint8_t* WAVEFORMS = (uint8_t*)0x0FFE4; | ||
uint8_t* SFX = (uint8_t*)0x100E4; | ||
uint8_t* MUSIC_PATTERNS = (uint8_t*)0x11164; | ||
uint8_t* MUSIC_TRACKS = (uint8_t*)0x13E64; | ||
uint8_t* SOUND_STATE = (uint8_t*)0x13FFC; | ||
uint8_t* STEREO_VOLUME = (uint8_t*)0x14000; | ||
uint8_t* PERSISTENT_MEMORY = (uint8_t*)0x14004; | ||
uint8_t* SPRITE_FLAGS = (uint8_t*)0x14404; | ||
uint8_t* SYSTEM_FONT = (uint8_t*)0x14604; | ||
uint8_t* WASM_FREE_RAM = (uint8_t*)0x18000; // 160kb | ||
|
||
// Functions. | ||
WASM_IMPORT("btn") | ||
int32_t btn(int32_t id); | ||
|
||
WASM_IMPORT("btnp") | ||
bool btnp(int32_t id, int32_t hold, int32_t period); | ||
|
||
WASM_IMPORT("circ") | ||
void circ(int32_t x, int32_t y, int32_t radius, int32_t color); | ||
|
||
WASM_IMPORT("circb") | ||
void circb(int32_t x, int32_t y, int32_t radius, int32_t color); | ||
|
||
WASM_IMPORT("clip") | ||
void clip(int32_t x, int32_t y, int32_t w, int32_t h); | ||
|
||
WASM_IMPORT("cls") | ||
void cls(int32_t color); | ||
|
||
WASM_IMPORT("exit") | ||
void exit(); | ||
|
||
WASM_IMPORT("elli") | ||
void elli(int32_t x, int32_t y, int32_t a, int32_t b, int32_t color); | ||
|
||
WASM_IMPORT("ellib") | ||
void ellib(int32_t x, int32_t y, int32_t a, int32_t b, int32_t color); | ||
|
||
WASM_IMPORT("fget") | ||
bool fget(int32_t id, uint8_t flag); | ||
|
||
WASM_IMPORT("font") | ||
int32_t font(const char* text, int32_t x, int32_t y, uint32_t* transcolors, int32_t colorcount, int32_t width, int32_t height, bool fixed, int32_t scale, bool alt); | ||
|
||
WASM_IMPORT("fset") | ||
bool fset(int32_t id, uint8_t flag, bool value); | ||
|
||
WASM_IMPORT("key") | ||
bool key(int32_t keycode); | ||
|
||
WASM_IMPORT("keyp") | ||
bool keyp(int32_t keycode, int32_t hold, int32_t period); | ||
|
||
WASM_IMPORT("line") | ||
void line(float x0, float y0, float x1, float y1, int8_t color); | ||
|
||
WASM_IMPORT("map") | ||
void map(int32_t x, int32_t y, int32_t w, int32_t h, int32_t sx, int32_t sy, uint32_t* transcolors, int32_t colorcount, int32_t scale, int32_t remap); | ||
|
||
WASM_IMPORT("memcpy") | ||
void memcpy_tic(uint32_t copyto, uint32_t copyfrom, uint32_t length); | ||
|
||
WASM_IMPORT("memset") | ||
void memset_tic(uint32_t addr, uint8_t value, uint32_t length); | ||
|
||
WASM_IMPORT("mget") | ||
int32_t mget(int32_t x, int32_t y); | ||
|
||
WASM_IMPORT("mouse") | ||
void mouse(MouseData* data); | ||
|
||
WASM_IMPORT("mset") | ||
void mset(int32_t x, int32_t y, bool value); | ||
|
||
WASM_IMPORT("music") | ||
void music(int32_t track, int32_t frame, int32_t row, bool loop, bool sustain, int32_t tempo, int32_t speed); | ||
|
||
WASM_IMPORT("peek") | ||
uint8_t peek(int32_t addr, int32_t bits); | ||
|
||
WASM_IMPORT("peek4") | ||
uint8_t peek4(uint32_t addr4); | ||
|
||
WASM_IMPORT("peek2") | ||
uint8_t peek2(uint32_t addr2); | ||
|
||
WASM_IMPORT("peek1") | ||
uint8_t peek1(uint32_t bitaddr); | ||
|
||
WASM_IMPORT("pix") | ||
void pix(int32_t x, int32_t y, int32_t color); | ||
|
||
WASM_IMPORT("pmem") | ||
uint32_t pmem(uint32_t index, uint32_t value); | ||
|
||
WASM_IMPORT("poke") | ||
void poke(int32_t addr, int8_t value, int8_t bits); | ||
|
||
WASM_IMPORT("poke4") | ||
void poke4(int32_t addr4, int8_t value); | ||
|
||
WASM_IMPORT("poke2") | ||
void poke2(int32_t addr2, int8_t value); | ||
|
||
WASM_IMPORT("poke1") | ||
void poke1(int32_t bitaddr, int8_t value); | ||
|
||
WASM_IMPORT("print") | ||
int32_t print(const char* txt, int32_t x, int32_t y, int32_t color, int32_t fixed, int32_t scale, int32_t alt); | ||
|
||
WASM_IMPORT("rect") | ||
void rect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t color); | ||
|
||
WASM_IMPORT("rectb") | ||
void rectb(int32_t x, int32_t y, int32_t w, int32_t h, int32_t color); | ||
|
||
WASM_IMPORT("reset") | ||
void reset(); | ||
|
||
WASM_IMPORT("sfx") | ||
void sfx(int32_t id, int32_t note, int32_t octave, int32_t duration, int32_t channel, int32_t volumeLeft, int32_t volumeRight, int32_t speed); | ||
|
||
WASM_IMPORT("spr") | ||
void spr(int32_t id, int32_t x, int32_t y, uint8_t* transcolors, uint32_t colorcount, int32_t scale, int32_t flip, int32_t rotate, int32_t w, int32_t h); | ||
|
||
WASM_IMPORT("sync") | ||
void sync(int32_t mask, int32_t bank, bool tocart); | ||
|
||
WASM_IMPORT("trace") | ||
void trace(const char* txt, int32_t color); | ||
|
||
WASM_IMPORT("ttri") | ||
void ttri(float x1, float y1, float x2, float y2, float x3, float y3, float u1, float v1, float u2, float v2, float u3, float v3, int32_t texsrc, uint32_t* transcolors, int32_t colorcount, float z1, float z2, float z3, bool persp); | ||
|
||
WASM_IMPORT("tri") | ||
void tri(float x1, float y1, float x2, float y2, float x3, float y3, int32_t color); | ||
|
||
WASM_IMPORT("trib") | ||
void trib(float x1, float y1, float x2, float y2, float x3, float y3, int32_t color); | ||
|
||
WASM_IMPORT("time") | ||
float time(); | ||
|
||
WASM_IMPORT("tstamp") | ||
int32_t tstamp(); | ||
|
||
WASM_IMPORT("vbank") | ||
int32_t vbank(int32_t bank); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
-- desc: WASM Introduction | ||
-- script: wasm | ||
|
||
""""""""""""""""""""""""""""""""""""""" | ||
WASM is a binary format. The demo | ||
binary code is embedded in this | ||
cartridge, the source code is not. | ||
Run the cart to see the demo. | ||
|
||
This demo exits for completeness, but | ||
you can't (yet) develop WASM projects | ||
using the built-in editor. | ||
|
||
The code used to build this project | ||
can be found in the TIC-80 repo: | ||
|
||
https://github.com/nesbox/TIC-80/templates/c | ||
|
||
This demo was built with C, but many | ||
languages are supported. You simply | ||
build your project with your external | ||
compiler, then import the final WASM | ||
binary into your cartridge: | ||
|
||
import binary out.wasm | ||
|
||
See README.md for details. | ||
|
||
To learn more visit our Wiki and | ||
the 'Getting Started with WASM' page. | ||
|
||
" | ||
-- <TILES> | ||
-- 001:eccccccccc888888caaaaaaaca888888cacccccccacc0ccccacc0ccccacc0ccc | ||
-- 002:ccccceee8888cceeaaaa0cee888a0ceeccca0ccc0cca0c0c0cca0c0c0cca0c0c | ||
-- 003:eccccccccc888888caaaaaaaca888888cacccccccacccccccacc0ccccacc0ccc | ||
-- 004:ccccceee8888cceeaaaa0cee888a0ceeccca0cccccca0c0c0cca0c0c0cca0c0c | ||
-- 017:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec | ||
-- 018:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee | ||
-- 019:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec | ||
-- 020:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee | ||
-- </TILES> | ||
|
||
-- <WAVES> | ||
-- 000:00000000ffffffff00000000ffffffff | ||
-- 001:0123456789abcdeffedcba9876543210 | ||
-- 002:0123456789abcdef0123456789abcdef | ||
-- </WAVES> | ||
|
||
-- <SFX> | ||
-- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000 | ||
-- </SFX> | ||
|
||
-- <PALETTE> | ||
-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57 | ||
-- </PALETTE> | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would
tic_memcpy
make more sense? I'm not sure, but this is one of the few pieces that caught my eye. I assume this is because of the C built-inmemcpy
function?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, it is due to conflicts with the C standard library. While
tic_memcpy
, would be the more normal way to say the function name, in practice when you want to usememcpy
you would probably just start typing it without realizingtic_
should be in front, whereas it being treated as a suffix allows for IntelliSense to catch it.Having it be a suffix too makes it feel less inconsistent. If two of the function names began with
tic_
, then it would be strange for not all of them to begin with this prefix.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You make a good case...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As pointed out elsewhere C's own native
memcpy
would likely be sufficient - there isn't supposed to be any magic.... is tapping into that a possibility?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know that was allowed for this, I assumed TIC's memcpy and memset were special.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They shouldn't be. The WASM VM has access to all the RAM - it should be able to move it about at at will . Really the
memcpy
andmemset
make a whole lot less sense when you're in C as you have directly access to RAM. Remember most people are using scripting runtime so the only way to get to the devices 96kb of MMIO is via these special functions, where-as in the WASM runtime all the memory is just freely available.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless the API is different though, that's a sticky point... we'd prefer the same TIC API arguments, but if we used native memcpy behind the scenes I think that'd be fine. So is that doable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have removed these TIC functions and tested the standard memset and it works fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets just add a mention to the README that for simplicity and to avoid conflicts one should use the standard C memory functions rather than the TIC api ones...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the README. I think the wording is ok, but I'm not sure.