ppuClear call from zig to c# simulator; not yet implemented in simulator; also breakpoints are not working in vs-code
This commit is contained in:
+165
-1
@@ -1,10 +1,14 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "nova64_framebuffer.h"
|
||||
#include "nova64_internal.h"
|
||||
#include "projdefs.h"
|
||||
#include "task.h"
|
||||
#include "wasm_export.h"
|
||||
#include <string.h>
|
||||
|
||||
/* ========================================================================== */
|
||||
/* Core Native Callbacks */
|
||||
/* ========================================================================== */
|
||||
|
||||
static void native_yield(wasm_exec_env_t exec_env, uint32_t timeout_ms) {
|
||||
if (timeout_ms == 0) {
|
||||
@@ -28,10 +32,170 @@ static void native_log(wasm_exec_env_t exec_env, const char *message) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* PPU Native Callbacks */
|
||||
/* ========================================================================== */
|
||||
|
||||
static void native_ppu_fill_rect(wasm_exec_env_t exec_env, int32_t x, int32_t y,
|
||||
int32_t w, int32_t h, uint32_t color) {
|
||||
(void)exec_env;
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->fill_rect) {
|
||||
ppu->fill_rect(nova64_framebuffer.back_buffer, NOVA64_DISPLAY_WIDTH, x, y,
|
||||
w, h, (pixel_t)color);
|
||||
}
|
||||
}
|
||||
|
||||
static void native_ppu_clear(wasm_exec_env_t exec_env, uint32_t color) {
|
||||
(void)exec_env;
|
||||
nova64_framebuffer_clear((pixel_t)color);
|
||||
}
|
||||
|
||||
static void native_ppu_blit(wasm_exec_env_t exec_env, uint32_t src_wasm_ptr,
|
||||
uint32_t src_stride, int32_t src_x, int32_t src_y,
|
||||
int32_t dst_x, int32_t dst_y, int32_t w,
|
||||
int32_t h) {
|
||||
wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
const pixel_t *src_native = (const pixel_t *)wasm_runtime_addr_app_to_native(
|
||||
module_inst, src_wasm_ptr);
|
||||
|
||||
if (!src_native)
|
||||
return;
|
||||
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->blit) {
|
||||
ppu->blit(src_native, src_stride, nova64_framebuffer.back_buffer,
|
||||
NOVA64_DISPLAY_WIDTH, src_x, src_y, dst_x, dst_y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
static void native_ppu_blit_colorkey(wasm_exec_env_t exec_env,
|
||||
uint32_t src_wasm_ptr, uint32_t src_stride,
|
||||
int32_t src_x, int32_t src_y,
|
||||
int32_t dst_x, int32_t dst_y, int32_t w,
|
||||
int32_t h, uint32_t key_color) {
|
||||
wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
const pixel_t *src_native = (const pixel_t *)wasm_runtime_addr_app_to_native(
|
||||
module_inst, src_wasm_ptr);
|
||||
|
||||
if (!src_native)
|
||||
return;
|
||||
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->blit_colorkey) {
|
||||
ppu->blit_colorkey(src_native, src_stride, nova64_framebuffer.back_buffer,
|
||||
NOVA64_DISPLAY_WIDTH, src_x, src_y, dst_x, dst_y, w, h,
|
||||
(pixel_t)key_color);
|
||||
}
|
||||
}
|
||||
|
||||
static void native_ppu_blend(wasm_exec_env_t exec_env, uint32_t src_wasm_ptr,
|
||||
uint32_t src_stride, int32_t src_x, int32_t src_y,
|
||||
int32_t dst_x, int32_t dst_y, int32_t w, int32_t h,
|
||||
uint32_t global_alpha) {
|
||||
wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
const pixel_t *src_native = (const pixel_t *)wasm_runtime_addr_app_to_native(
|
||||
module_inst, src_wasm_ptr);
|
||||
|
||||
if (!src_native)
|
||||
return;
|
||||
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->blend) {
|
||||
ppu->blend(src_native, src_stride, nova64_framebuffer.back_buffer,
|
||||
NOVA64_DISPLAY_WIDTH, src_x, src_y, dst_x, dst_y, w, h,
|
||||
(uint8_t)global_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
static void native_ppu_blit_transform(wasm_exec_env_t exec_env,
|
||||
uint32_t src_wasm_ptr,
|
||||
uint32_t src_stride, int32_t src_x,
|
||||
int32_t src_y, int32_t dst_x,
|
||||
int32_t dst_y, int32_t w, int32_t h,
|
||||
uint32_t transform) {
|
||||
wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
const pixel_t *src_native = (const pixel_t *)wasm_runtime_addr_app_to_native(
|
||||
module_inst, src_wasm_ptr);
|
||||
|
||||
if (!src_native)
|
||||
return;
|
||||
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->blit_transform) {
|
||||
ppu->blit_transform(src_native, src_stride, nova64_framebuffer.back_buffer,
|
||||
NOVA64_DISPLAY_WIDTH, src_x, src_y, dst_x, dst_y, w, h,
|
||||
(nova64_transform_t)transform);
|
||||
}
|
||||
}
|
||||
|
||||
static void native_ppu_blit_scale(wasm_exec_env_t exec_env,
|
||||
uint32_t src_wasm_ptr, uint32_t src_stride,
|
||||
int32_t src_w, int32_t src_h, int32_t dst_x,
|
||||
int32_t dst_y, int32_t dst_w, int32_t dst_h) {
|
||||
wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env);
|
||||
const pixel_t *src_native = (const pixel_t *)wasm_runtime_addr_app_to_native(
|
||||
module_inst, src_wasm_ptr);
|
||||
|
||||
if (!src_native)
|
||||
return;
|
||||
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->blit_scale) {
|
||||
ppu->blit_scale(src_native, src_stride, src_w, src_h,
|
||||
nova64_framebuffer.back_buffer, NOVA64_DISPLAY_WIDTH, dst_x,
|
||||
dst_y, dst_w, dst_h);
|
||||
}
|
||||
}
|
||||
|
||||
static void native_ppu_wait_idle(wasm_exec_env_t exec_env) {
|
||||
(void)exec_env;
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->wait_idle) {
|
||||
ppu->wait_idle();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t native_ppu_is_busy(wasm_exec_env_t exec_env) {
|
||||
(void)exec_env;
|
||||
const nova64_ppu_interface_t *ppu = nova64_get_ppu_interface();
|
||||
if (ppu && ppu->is_busy) {
|
||||
return ppu->is_busy() ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void native_framebuffer_swap(wasm_exec_env_t exec_env) {
|
||||
(void)exec_env;
|
||||
nova64_framebuffer_swap();
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* WAMR Native Symbols Table */
|
||||
/* ========================================================================== */
|
||||
|
||||
static NativeSymbol native_symbols[] = {
|
||||
{"nova64_yield", (void *)native_yield, "(i)", NULL},
|
||||
{"nova64_log", (void *)native_log, "($)", NULL},
|
||||
// { "flush_framebuffer", (void*)native_flush_framebuffer, "()", NULL }
|
||||
|
||||
// Framebuffer Controls
|
||||
{"nova64_ppu_clear", (void *)native_ppu_clear, "(i)", NULL},
|
||||
{"nova64_framebuffer_swap", (void *)native_framebuffer_swap, "()", NULL},
|
||||
|
||||
// PPU Drawing Primitives
|
||||
{"nova64_ppu_fill_rect", (void *)native_ppu_fill_rect, "(iiiii)", NULL},
|
||||
{"nova64_ppu_blit", (void *)native_ppu_blit, "(iiiiiiiii)", NULL},
|
||||
{"nova64_ppu_blit_colorkey", (void *)native_ppu_blit_colorkey,
|
||||
"(iiiiiiiiii)", NULL},
|
||||
{"nova64_ppu_blend", (void *)native_ppu_blend, "(iiiiiiiiii)", NULL},
|
||||
{"nova64_ppu_blit_transform", (void *)native_ppu_blit_transform,
|
||||
"(iiiiiiiiii)", NULL},
|
||||
{"nova64_ppu_blit_scale", (void *)native_ppu_blit_scale, "(iiiiiiiii)",
|
||||
NULL},
|
||||
|
||||
// Hardware Sync
|
||||
{"nova64_ppu_wait_idle", (void *)native_ppu_wait_idle, "()", NULL},
|
||||
{"nova64_ppu_is_busy", (void *)native_ppu_is_busy, "()i", NULL},
|
||||
};
|
||||
|
||||
void nova64_register_imports(void) {
|
||||
|
||||
@@ -13,7 +13,6 @@ internal static class Program
|
||||
return SdRoot / $"slot{slotIdx}" / normalizedPath;
|
||||
}
|
||||
|
||||
private static readonly Nova64.DisplayFlushDelegate DisplayFlush = (buffer, width, height) => { };
|
||||
private static readonly Nova64.AudioOutputDelegate AudioOutput = (samples, count) => { };
|
||||
private static readonly Nova64.SdReadFileDelegate SdReadFile = (slotIdx, filePath, destinationBuffer, destinationLength) =>
|
||||
{
|
||||
@@ -47,6 +46,7 @@ internal static class Program
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly Nova64.SdGetFileSizeDelegate SdGetFileSize = (slotIdx, filePath) =>
|
||||
{
|
||||
var path = GetSlotFilePath(slotIdx, filePath);
|
||||
@@ -69,6 +69,7 @@ internal static class Program
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly Nova64.CartridgeStatusDelegate CartridgeStatus = (slotIdx, isInserted) => { };
|
||||
private static readonly Nova64.LogMessageDelegate LogMessage = (message) =>
|
||||
{
|
||||
@@ -76,6 +77,11 @@ internal static class Program
|
||||
Console.Out.Flush();
|
||||
};
|
||||
|
||||
private static readonly Nova64.PpuFillRectDelegate FillRect = (dst, dstStride, x, y, w, h, color) =>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
private static GCHandle? _ioHandle;
|
||||
private static GCHandle? _ppuHandle;
|
||||
private static Thread? _coreThread;
|
||||
@@ -129,7 +135,7 @@ internal static class Program
|
||||
|
||||
var ppuInterface = new Nova64.Nova64PpuInterface
|
||||
{
|
||||
|
||||
fill_rect = Marshal.GetFunctionPointerForDelegate(FillRect),
|
||||
};
|
||||
|
||||
_ppuHandle = GCHandle.Alloc(ppuInterface, GCHandleType.Pinned);
|
||||
|
||||
Binary file not shown.
+3
-1
@@ -5,7 +5,9 @@ pub fn main() void {
|
||||
while (true) {
|
||||
nova64.log("Hello from Zig!");
|
||||
// nova64.yield();
|
||||
nova64.sleep(50);
|
||||
nova64.ppuClear(0x00);
|
||||
nova64.ppuSwapBuffers();
|
||||
nova64.sleep(16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+198
-4
@@ -1,8 +1,104 @@
|
||||
pub extern "nova64" fn nova64_yield(timeout_ms: u32) void;
|
||||
pub extern "nova64" fn nova64_log(message: [*]const u8) void;
|
||||
const std = @import("std");
|
||||
|
||||
pub fn log(message: []const u8) void {
|
||||
nova64_log(message.ptr);
|
||||
// ============================================================================
|
||||
// Types & Enums
|
||||
// ============================================================================
|
||||
|
||||
/// RGB565 Color Format (16-bit)
|
||||
pub const Color = u16;
|
||||
|
||||
/// Transformation flags for hardware-accelerated sprite operations.
|
||||
pub const Transform = packed struct(u32) {
|
||||
flip_h: bool = false,
|
||||
flip_v: bool = false,
|
||||
rot_90: bool = false,
|
||||
rot_180: bool = false,
|
||||
rot_270: bool = false,
|
||||
_padding: u27 = 0,
|
||||
};
|
||||
|
||||
// Common Transform Constants
|
||||
pub const TRANSFORM_NONE = Transform{};
|
||||
pub const TRANSFORM_FLIP_H = Transform{ .flip_h = true };
|
||||
pub const TRANSFORM_FLIP_V = Transform{ .flip_v = true };
|
||||
|
||||
// ============================================================================
|
||||
// Low-Level C-Imports (Raw WAMR Native Symbol Bindings)
|
||||
// ============================================================================
|
||||
|
||||
pub extern "nova64" fn nova64_yield(timeout_ms: u32) void;
|
||||
pub extern "nova64" fn nova64_log(message: [*:0]const u8) void;
|
||||
|
||||
// Framebuffer Controls
|
||||
pub extern "nova64" fn nova64_ppu_clear(color: u32) void;
|
||||
pub extern "nova64" fn nova64_framebuffer_swap() void;
|
||||
|
||||
// PPU Drawing Primitives
|
||||
pub extern "nova64" fn nova64_ppu_fill_rect(x: i32, y: i32, w: i32, h: i32, color: u32) void;
|
||||
pub extern "nova64" fn nova64_ppu_blit(
|
||||
src_ptr: [*]const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
) void;
|
||||
pub extern "nova64" fn nova64_ppu_blit_colorkey(
|
||||
src_ptr: [*]const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
key_color: u32,
|
||||
) void;
|
||||
pub extern "nova64" fn nova64_ppu_blend(
|
||||
src_ptr: [*]const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
global_alpha: u32,
|
||||
) void;
|
||||
pub extern "nova64" fn nova64_ppu_blit_transform(
|
||||
src_ptr: [*]const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
transform: Transform,
|
||||
) void;
|
||||
pub extern "nova64" fn nova64_ppu_blit_scale(
|
||||
src_ptr: [*]const Color,
|
||||
src_stride: u32,
|
||||
src_w: i32,
|
||||
src_h: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
dst_w: i32,
|
||||
dst_h: i32,
|
||||
) void;
|
||||
|
||||
// Hardware Sync
|
||||
pub extern "nova64" fn nova64_ppu_wait_idle() void;
|
||||
pub extern "nova64" fn nova64_ppu_is_busy() u32;
|
||||
|
||||
// ============================================================================
|
||||
// High-Level Idiomatic Zig API
|
||||
// ============================================================================
|
||||
|
||||
pub fn log(message: [*:0]const u8) void {
|
||||
nova64_log(message);
|
||||
}
|
||||
|
||||
pub fn sleep(timeout_ms: u32) void {
|
||||
@@ -12,3 +108,101 @@ pub fn sleep(timeout_ms: u32) void {
|
||||
pub fn yield() void {
|
||||
nova64_yield(0);
|
||||
}
|
||||
|
||||
/// Swaps the front and back buffer to display the rendered frame.
|
||||
pub fn ppuSwapBuffers() void {
|
||||
nova64_framebuffer_swap();
|
||||
}
|
||||
|
||||
/// Clears the back buffer with a solid RGB565 color.
|
||||
pub fn ppuClear(color: Color) void {
|
||||
nova64_ppu_clear(@as(u32, color));
|
||||
}
|
||||
|
||||
/// Fills a rectangle on the back buffer with a solid RGB565 color.
|
||||
pub fn ppuFillRect(x: i32, y: i32, w: i32, h: i32, color: Color) void {
|
||||
nova64_ppu_fill_rect(x, y, w, h, @as(u32, color));
|
||||
}
|
||||
|
||||
/// Opaque block image transfer from a pixel buffer to the back buffer.
|
||||
pub fn ppuBlit(
|
||||
src: []const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
) void {
|
||||
nova64_ppu_blit(src.ptr, src_stride, src_x, src_y, dst_x, dst_y, w, h);
|
||||
}
|
||||
|
||||
/// Transparent sprite blitting using color keying.
|
||||
pub fn ppuBlitColorKey(
|
||||
src: []const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
key_color: Color,
|
||||
) void {
|
||||
nova64_ppu_blit_colorkey(src.ptr, src_stride, src_x, src_y, dst_x, dst_y, w, h, @as(u32, key_color));
|
||||
}
|
||||
|
||||
/// Alpha-blended sprite composition (alpha: 0 = transparent, 255 = opaque).
|
||||
pub fn ppuBlend(
|
||||
src: []const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
alpha: u8,
|
||||
) void {
|
||||
nova64_ppu_blend(src.ptr, src_stride, src_x, src_y, dst_x, dst_y, w, h, @as(u32, alpha));
|
||||
}
|
||||
|
||||
/// Transformed image transfer (rotation & flipping).
|
||||
pub fn ppuBlitTransform(
|
||||
src: []const Color,
|
||||
src_stride: u32,
|
||||
src_x: i32,
|
||||
src_y: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
transform: Transform,
|
||||
) void {
|
||||
nova64_ppu_blit_transform(src.ptr, src_stride, src_x, src_y, dst_x, dst_y, w, h, transform);
|
||||
}
|
||||
|
||||
/// Hardware-accelerated image scaling/resizing.
|
||||
pub fn ppuBlitScale(
|
||||
src: []const Color,
|
||||
src_stride: u32,
|
||||
src_w: i32,
|
||||
src_h: i32,
|
||||
dst_x: i32,
|
||||
dst_y: i32,
|
||||
dst_w: i32,
|
||||
dst_h: i32,
|
||||
) void {
|
||||
nova64_ppu_blit_scale(src.ptr, src_stride, src_w, src_h, dst_x, dst_y, dst_w, dst_h);
|
||||
}
|
||||
|
||||
/// Blocks execution until the PPU/DMA2D hardware engine finishes all operations.
|
||||
pub fn ppuWaitIdle() void {
|
||||
nova64_ppu_wait_idle();
|
||||
}
|
||||
|
||||
/// Checks if the PPU hardware engine is currently busy.
|
||||
pub fn ppuIsBusy() bool {
|
||||
return nova64_ppu_is_busy() != 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user