Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ sec: $(BUILDDIR) sec/*.h sec/*.c | $(BUILDDIR)

tools: $(BUILDDIR) $(TOOLSDIR)/*.c vm/*.h | $(BUILDDIR)
$(CC) $(CFLAGS) $(TINY16_LDFLAGS) -o $(BUILDDIR)/png2tiles$(EXE_EXT) $(TOOLSDIR)/png2tiles.c -lm
$(CC) $(CFLAGS) $(TINY16_LDFLAGS) -o $(BUILDDIR)/midi2music$(EXE_EXT) $(TOOLSDIR)/midi2music.c -lm

emulator: $(BUILDDIR) vm/*.c vm/*.h emulator/*.c $(RAYLIB_LIB_NATIVE) | $(BUILDDIR)
$(CC) $(CFLAGS) $(TINY16_LDFLAGS) $(RAYLIB_INCLUDE) -o $(BUILDDIR)/tiny16-emu$(EXE_EXT) \
Expand Down Expand Up @@ -157,8 +158,11 @@ EXAMPLES_ASM_OUTPUTS := $(patsubst examples/asm/%.asm,$(BUILDDIR)/%.tiny16,$(EXA
EXAMPLES_SE := $(wildcard examples/se/*.se)
EXAMPLES_SE_OUTPUTS := $(patsubst examples/se/%.se,$(BUILDDIR)/%_se.tiny16,$(EXAMPLES_SE))

EXAMPLES_ASSETS := $(wildcard examples/assets/*.png)
EXAMPLES_ASSETS_OUTPUTS := $(patsubst examples/assets/%.png,examples/includes/%.inc,$(EXAMPLES_ASSETS))
EXAMPLES_ASSETS_PNG := $(wildcard examples/assets/*.png)
EXAMPLES_ASSETS_PNG_OUTPUTS := $(patsubst examples/assets/%.png,examples/includes/%.inc,$(EXAMPLES_ASSETS_PNG))

EXAMPLES_ASSETS_MIDI := $(wildcard examples/assets/*.mid)
EXAMPLES_ASSETS_MIDI_OUTPUTS := $(patsubst examples/assets/%.mid,stdlib/se/%.se,$(EXAMPLES_ASSETS_MIDI))

EXAMPLE_INCLUDES := $(wildcard stdlib/*.inc) $(wildcard examples/includes/*.inc) $(wildcard asm/tutorial/includes/*.inc)

Expand All @@ -178,11 +182,15 @@ $(BUILDDIR)/%_se.tiny16: examples/se/%.se $(EXAMPLE_INCLUDES) | $(BUILDDIR)
$(BUILDDIR)/tiny16-asm$(EXE_EXT) $(BUILDDIR)/$*_se.asm $@

# PNG -> INC: convert PNG assets to assembly include files
examples-assets: tools $(EXAMPLES_ASSETS_OUTPUTS)
# MIDI -> SE: convert MIDI assets to S-expression music modules
examples-assets: tools $(EXAMPLES_ASSETS_PNG_OUTPUTS) $(EXAMPLES_ASSETS_MIDI_OUTPUTS)

examples/includes/%.inc: examples/assets/%.png | tools
$(BUILDDIR)/png2tiles$(EXE_EXT) $< $@

stdlib/se/%.se: examples/assets/%.mid | tools
$(BUILDDIR)/midi2music$(EXE_EXT) $< -n $* -v 5 -s 0.5 -o $@

$(RAYLIB_LIB_NATIVE):
@echo "Building raylib for native..."
@if [ -f "$(RAYLIB_LIB_WEB)" ]; then \
Expand Down
59 changes: 3 additions & 56 deletions emulator/tiny16_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,12 @@
// Global pointer for audio callback (raylib doesn't support user data in callback)
static Tiny16Emulator* g_emu = NULL;

#define TINY16_AUDIO_RING_MASK (TINY16_AUDIO_RING_FRAMES - 1u)

static void tiny16_audio_ring_write(Tiny16Emulator* emu, const float* samples, uint32_t frames) {
uint32_t write = emu->audio_write;
uint32_t read = emu->audio_read;
uint32_t free_frames = TINY16_AUDIO_RING_FRAMES - (write - read);
if (free_frames == 0) return;
if (frames > free_frames) frames = free_frames;
for (uint32_t i = 0; i < frames; i++) {
emu->audio_ring[write & TINY16_AUDIO_RING_MASK] = samples[i];
write++;
}
emu->audio_write = write;
}

static uint32_t tiny16_audio_ring_read(Tiny16Emulator* emu, float* buffer, uint32_t frames) {
uint32_t write = emu->audio_write;
uint32_t read = emu->audio_read;
uint32_t available = write - read;
if (available == 0) return 0;
if (frames > available) frames = available;
for (uint32_t i = 0; i < frames; i++) {
buffer[i] = emu->audio_ring[read & TINY16_AUDIO_RING_MASK];
read++;
}
emu->audio_read = read;
return frames;
}

static void tiny16_audio_callback(void* buffer, unsigned int frames) {
if (g_emu) {
float* out = (float*)buffer;
uint32_t got = tiny16_audio_ring_read(g_emu, out, frames);
if (got < frames) {
memset(out + got, 0, (frames - got) * sizeof(float));
}
} else {
memset(buffer, 0, frames * sizeof(float));
}
}

static void tiny16_emu_audio_produce(Tiny16Emulator* emu, uint32_t cpu_cycles) {
if (cpu_cycles == 0) return;
uint32_t frames_needed =
tiny16_apu_samples_for_cycles(&emu->vm->apu, cpu_cycles, TINY16_CPU_HZ);
if (frames_needed == 0) return;

float temp[1024];
while (frames_needed > 0) {
uint32_t chunk = frames_needed > 1024 ? 1024 : frames_needed;
tiny16_apu_generate_samples(&emu->vm->apu, temp, chunk);
tiny16_audio_ring_write(emu, temp, chunk);
frames_needed -= chunk;
tiny16_apu_generate_samples(&g_emu->vm->apu, (float*)buffer, frames);
return;
}
memset(buffer, 0, frames * sizeof(float));
}

Tiny16Emulator* tiny16_emu_create(Tiny16VM* vm, bool program_loaded) {
Expand All @@ -73,8 +25,6 @@ Tiny16Emulator* tiny16_emu_create(Tiny16VM* vm, bool program_loaded) {
emu->program_loaded = program_loaded;
emu->audio_enabled = false;
memset(emu->back_buffer, 0, sizeof(emu->back_buffer));
emu->audio_read = 0;
emu->audio_write = 0;

// Pre-compute RGB332 -> RGBA lookup table
for (int i = 0; i < 256; i++) {
Expand Down Expand Up @@ -225,15 +175,12 @@ void tiny16_emu_update_frame(Tiny16Emulator* emu) {

tiny16_emu_update_input(vm);

uint32_t instr_executed = 0;
for (uint32_t step = 0; step < instr_this_frame; ++step) {
if (!tiny16_vm_step(vm)) {
emu->paused = true;
break;
}
instr_executed++;
}
tiny16_emu_audio_produce(emu, instr_executed);
}

BeginDrawing();
Expand Down
4 changes: 0 additions & 4 deletions emulator/tiny16_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#define TINY16_EMU_SCREEN_HEIGHT (TINY16_EMU_PIXEL_HEIGHT * 8)
#define TINY16_EMU_TARGET_IPS (60.0f * 30000) // 1.8M IPS = ~30000 instr/frame at 60 FPS
#define TINY16_CPU_HZ 1800000u
#define TINY16_AUDIO_RING_FRAMES 16384u

typedef struct {
Tiny16VM* vm;
Expand All @@ -26,9 +25,6 @@ typedef struct {
bool paused;
bool program_loaded;
bool audio_enabled;
float audio_ring[TINY16_AUDIO_RING_FRAMES];
volatile uint32_t audio_read;
volatile uint32_t audio_write;
} Tiny16Emulator;

Tiny16Emulator* tiny16_emu_create(Tiny16VM* vm, bool program_loaded);
Expand Down
Loading
Loading