Add agnes NES emulator (very slow).

Add -W <n> -H <n> width and height options to host-sdl
This commit is contained in:
Toby Jaffey 2025-12-15 00:37:12 +00:00
parent 2e90bfa812
commit 035608b04a
14 changed files with 3491 additions and 3 deletions

View file

@ -0,0 +1,436 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* \file SDL_scancode.h
*
* \brief Defines keyboard scancodes.
*/
#ifndef SDL_scancode_h_
#define SDL_scancode_h_
//#include <SDL3/SDL_stdinc.h>
/**
* \brief The SDL keyboard scancode representation.
*
* Values of this type are used to represent keyboard keys, among other places
* in the \link SDL_Keysym::scancode key.keysym.scancode \endlink field of the
* SDL_Event structure.
*
* The values in this enumeration are based on the USB usage page standard:
* https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
*/
typedef enum
{
SDL_SCANCODE_UNKNOWN = 0,
/**
* \name Usage page 0x07
*
* These values are from usage page 0x07 (USB keyboard page).
*/
/* @{ */
SDL_SCANCODE_A = 4,
SDL_SCANCODE_B = 5,
SDL_SCANCODE_C = 6,
SDL_SCANCODE_D = 7,
SDL_SCANCODE_E = 8,
SDL_SCANCODE_F = 9,
SDL_SCANCODE_G = 10,
SDL_SCANCODE_H = 11,
SDL_SCANCODE_I = 12,
SDL_SCANCODE_J = 13,
SDL_SCANCODE_K = 14,
SDL_SCANCODE_L = 15,
SDL_SCANCODE_M = 16,
SDL_SCANCODE_N = 17,
SDL_SCANCODE_O = 18,
SDL_SCANCODE_P = 19,
SDL_SCANCODE_Q = 20,
SDL_SCANCODE_R = 21,
SDL_SCANCODE_S = 22,
SDL_SCANCODE_T = 23,
SDL_SCANCODE_U = 24,
SDL_SCANCODE_V = 25,
SDL_SCANCODE_W = 26,
SDL_SCANCODE_X = 27,
SDL_SCANCODE_Y = 28,
SDL_SCANCODE_Z = 29,
SDL_SCANCODE_1 = 30,
SDL_SCANCODE_2 = 31,
SDL_SCANCODE_3 = 32,
SDL_SCANCODE_4 = 33,
SDL_SCANCODE_5 = 34,
SDL_SCANCODE_6 = 35,
SDL_SCANCODE_7 = 36,
SDL_SCANCODE_8 = 37,
SDL_SCANCODE_9 = 38,
SDL_SCANCODE_0 = 39,
SDL_SCANCODE_RETURN = 40,
SDL_SCANCODE_ESCAPE = 41,
SDL_SCANCODE_BACKSPACE = 42,
SDL_SCANCODE_TAB = 43,
SDL_SCANCODE_SPACE = 44,
SDL_SCANCODE_MINUS = 45,
SDL_SCANCODE_EQUALS = 46,
SDL_SCANCODE_LEFTBRACKET = 47,
SDL_SCANCODE_RIGHTBRACKET = 48,
SDL_SCANCODE_BACKSLASH = 49, /**< Located at the lower left of the return
* key on ISO keyboards and at the right end
* of the QWERTY row on ANSI keyboards.
* Produces REVERSE SOLIDUS (backslash) and
* VERTICAL LINE in a US layout, REVERSE
* SOLIDUS and VERTICAL LINE in a UK Mac
* layout, NUMBER SIGN and TILDE in a UK
* Windows layout, DOLLAR SIGN and POUND SIGN
* in a Swiss German layout, NUMBER SIGN and
* APOSTROPHE in a German layout, GRAVE
* ACCENT and POUND SIGN in a French Mac
* layout, and ASTERISK and MICRO SIGN in a
* French Windows layout.
*/
SDL_SCANCODE_NONUSHASH = 50, /**< ISO USB keyboards actually use this code
* instead of 49 for the same key, but all
* OSes I've seen treat the two codes
* identically. So, as an implementor, unless
* your keyboard generates both of those
* codes and your OS treats them differently,
* you should generate SDL_SCANCODE_BACKSLASH
* instead of this code. As a user, you
* should not rely on this code because SDL
* will never generate it with most (all?)
* keyboards.
*/
SDL_SCANCODE_SEMICOLON = 51,
SDL_SCANCODE_APOSTROPHE = 52,
SDL_SCANCODE_GRAVE = 53, /**< Located in the top left corner (on both ANSI
* and ISO keyboards). Produces GRAVE ACCENT and
* TILDE in a US Windows layout and in US and UK
* Mac layouts on ANSI keyboards, GRAVE ACCENT
* and NOT SIGN in a UK Windows layout, SECTION
* SIGN and PLUS-MINUS SIGN in US and UK Mac
* layouts on ISO keyboards, SECTION SIGN and
* DEGREE SIGN in a Swiss German layout (Mac:
* only on ISO keyboards), CIRCUMFLEX ACCENT and
* DEGREE SIGN in a German layout (Mac: only on
* ISO keyboards), SUPERSCRIPT TWO and TILDE in a
* French Windows layout, COMMERCIAL AT and
* NUMBER SIGN in a French Mac layout on ISO
* keyboards, and LESS-THAN SIGN and GREATER-THAN
* SIGN in a Swiss German, German, or French Mac
* layout on ANSI keyboards.
*/
SDL_SCANCODE_COMMA = 54,
SDL_SCANCODE_PERIOD = 55,
SDL_SCANCODE_SLASH = 56,
SDL_SCANCODE_CAPSLOCK = 57,
SDL_SCANCODE_F1 = 58,
SDL_SCANCODE_F2 = 59,
SDL_SCANCODE_F3 = 60,
SDL_SCANCODE_F4 = 61,
SDL_SCANCODE_F5 = 62,
SDL_SCANCODE_F6 = 63,
SDL_SCANCODE_F7 = 64,
SDL_SCANCODE_F8 = 65,
SDL_SCANCODE_F9 = 66,
SDL_SCANCODE_F10 = 67,
SDL_SCANCODE_F11 = 68,
SDL_SCANCODE_F12 = 69,
SDL_SCANCODE_PRINTSCREEN = 70,
SDL_SCANCODE_SCROLLLOCK = 71,
SDL_SCANCODE_PAUSE = 72,
SDL_SCANCODE_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but
does send code 73, not 117) */
SDL_SCANCODE_HOME = 74,
SDL_SCANCODE_PAGEUP = 75,
SDL_SCANCODE_DELETE = 76,
SDL_SCANCODE_END = 77,
SDL_SCANCODE_PAGEDOWN = 78,
SDL_SCANCODE_RIGHT = 79,
SDL_SCANCODE_LEFT = 80,
SDL_SCANCODE_DOWN = 81,
SDL_SCANCODE_UP = 82,
SDL_SCANCODE_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards
*/
SDL_SCANCODE_KP_DIVIDE = 84,
SDL_SCANCODE_KP_MULTIPLY = 85,
SDL_SCANCODE_KP_MINUS = 86,
SDL_SCANCODE_KP_PLUS = 87,
SDL_SCANCODE_KP_ENTER = 88,
SDL_SCANCODE_KP_1 = 89,
SDL_SCANCODE_KP_2 = 90,
SDL_SCANCODE_KP_3 = 91,
SDL_SCANCODE_KP_4 = 92,
SDL_SCANCODE_KP_5 = 93,
SDL_SCANCODE_KP_6 = 94,
SDL_SCANCODE_KP_7 = 95,
SDL_SCANCODE_KP_8 = 96,
SDL_SCANCODE_KP_9 = 97,
SDL_SCANCODE_KP_0 = 98,
SDL_SCANCODE_KP_PERIOD = 99,
SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO
* keyboards have over ANSI ones,
* located between left shift and Y.
* Produces GRAVE ACCENT and TILDE in a
* US or UK Mac layout, REVERSE SOLIDUS
* (backslash) and VERTICAL LINE in a
* US or UK Windows layout, and
* LESS-THAN SIGN and GREATER-THAN SIGN
* in a Swiss German, German, or French
* layout. */
SDL_SCANCODE_APPLICATION = 101, /**< windows contextual menu, compose */
SDL_SCANCODE_POWER = 102, /**< The USB document says this is a status flag,
* not a physical key - but some Mac keyboards
* do have a power key. */
SDL_SCANCODE_KP_EQUALS = 103,
SDL_SCANCODE_F13 = 104,
SDL_SCANCODE_F14 = 105,
SDL_SCANCODE_F15 = 106,
SDL_SCANCODE_F16 = 107,
SDL_SCANCODE_F17 = 108,
SDL_SCANCODE_F18 = 109,
SDL_SCANCODE_F19 = 110,
SDL_SCANCODE_F20 = 111,
SDL_SCANCODE_F21 = 112,
SDL_SCANCODE_F22 = 113,
SDL_SCANCODE_F23 = 114,
SDL_SCANCODE_F24 = 115,
SDL_SCANCODE_EXECUTE = 116,
SDL_SCANCODE_HELP = 117, /**< AL Integrated Help Center */
SDL_SCANCODE_MENU = 118, /**< Menu (show menu) */
SDL_SCANCODE_SELECT = 119,
SDL_SCANCODE_STOP = 120, /**< AC Stop */
SDL_SCANCODE_AGAIN = 121, /**< AC Redo/Repeat */
SDL_SCANCODE_UNDO = 122, /**< AC Undo */
SDL_SCANCODE_CUT = 123, /**< AC Cut */
SDL_SCANCODE_COPY = 124, /**< AC Copy */
SDL_SCANCODE_PASTE = 125, /**< AC Paste */
SDL_SCANCODE_FIND = 126, /**< AC Find */
SDL_SCANCODE_MUTE = 127,
SDL_SCANCODE_VOLUMEUP = 128,
SDL_SCANCODE_VOLUMEDOWN = 129,
/* not sure whether there's a reason to enable these */
/* SDL_SCANCODE_LOCKINGCAPSLOCK = 130, */
/* SDL_SCANCODE_LOCKINGNUMLOCK = 131, */
/* SDL_SCANCODE_LOCKINGSCROLLLOCK = 132, */
SDL_SCANCODE_KP_COMMA = 133,
SDL_SCANCODE_KP_EQUALSAS400 = 134,
SDL_SCANCODE_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see
footnotes in USB doc */
SDL_SCANCODE_INTERNATIONAL2 = 136,
SDL_SCANCODE_INTERNATIONAL3 = 137, /**< Yen */
SDL_SCANCODE_INTERNATIONAL4 = 138,
SDL_SCANCODE_INTERNATIONAL5 = 139,
SDL_SCANCODE_INTERNATIONAL6 = 140,
SDL_SCANCODE_INTERNATIONAL7 = 141,
SDL_SCANCODE_INTERNATIONAL8 = 142,
SDL_SCANCODE_INTERNATIONAL9 = 143,
SDL_SCANCODE_LANG1 = 144, /**< Hangul/English toggle */
SDL_SCANCODE_LANG2 = 145, /**< Hanja conversion */
SDL_SCANCODE_LANG3 = 146, /**< Katakana */
SDL_SCANCODE_LANG4 = 147, /**< Hiragana */
SDL_SCANCODE_LANG5 = 148, /**< Zenkaku/Hankaku */
SDL_SCANCODE_LANG6 = 149, /**< reserved */
SDL_SCANCODE_LANG7 = 150, /**< reserved */
SDL_SCANCODE_LANG8 = 151, /**< reserved */
SDL_SCANCODE_LANG9 = 152, /**< reserved */
SDL_SCANCODE_ALTERASE = 153, /**< Erase-Eaze */
SDL_SCANCODE_SYSREQ = 154,
SDL_SCANCODE_CANCEL = 155, /**< AC Cancel */
SDL_SCANCODE_CLEAR = 156,
SDL_SCANCODE_PRIOR = 157,
SDL_SCANCODE_RETURN2 = 158,
SDL_SCANCODE_SEPARATOR = 159,
SDL_SCANCODE_OUT = 160,
SDL_SCANCODE_OPER = 161,
SDL_SCANCODE_CLEARAGAIN = 162,
SDL_SCANCODE_CRSEL = 163,
SDL_SCANCODE_EXSEL = 164,
SDL_SCANCODE_KP_00 = 176,
SDL_SCANCODE_KP_000 = 177,
SDL_SCANCODE_THOUSANDSSEPARATOR = 178,
SDL_SCANCODE_DECIMALSEPARATOR = 179,
SDL_SCANCODE_CURRENCYUNIT = 180,
SDL_SCANCODE_CURRENCYSUBUNIT = 181,
SDL_SCANCODE_KP_LEFTPAREN = 182,
SDL_SCANCODE_KP_RIGHTPAREN = 183,
SDL_SCANCODE_KP_LEFTBRACE = 184,
SDL_SCANCODE_KP_RIGHTBRACE = 185,
SDL_SCANCODE_KP_TAB = 186,
SDL_SCANCODE_KP_BACKSPACE = 187,
SDL_SCANCODE_KP_A = 188,
SDL_SCANCODE_KP_B = 189,
SDL_SCANCODE_KP_C = 190,
SDL_SCANCODE_KP_D = 191,
SDL_SCANCODE_KP_E = 192,
SDL_SCANCODE_KP_F = 193,
SDL_SCANCODE_KP_XOR = 194,
SDL_SCANCODE_KP_POWER = 195,
SDL_SCANCODE_KP_PERCENT = 196,
SDL_SCANCODE_KP_LESS = 197,
SDL_SCANCODE_KP_GREATER = 198,
SDL_SCANCODE_KP_AMPERSAND = 199,
SDL_SCANCODE_KP_DBLAMPERSAND = 200,
SDL_SCANCODE_KP_VERTICALBAR = 201,
SDL_SCANCODE_KP_DBLVERTICALBAR = 202,
SDL_SCANCODE_KP_COLON = 203,
SDL_SCANCODE_KP_HASH = 204,
SDL_SCANCODE_KP_SPACE = 205,
SDL_SCANCODE_KP_AT = 206,
SDL_SCANCODE_KP_EXCLAM = 207,
SDL_SCANCODE_KP_MEMSTORE = 208,
SDL_SCANCODE_KP_MEMRECALL = 209,
SDL_SCANCODE_KP_MEMCLEAR = 210,
SDL_SCANCODE_KP_MEMADD = 211,
SDL_SCANCODE_KP_MEMSUBTRACT = 212,
SDL_SCANCODE_KP_MEMMULTIPLY = 213,
SDL_SCANCODE_KP_MEMDIVIDE = 214,
SDL_SCANCODE_KP_PLUSMINUS = 215,
SDL_SCANCODE_KP_CLEAR = 216,
SDL_SCANCODE_KP_CLEARENTRY = 217,
SDL_SCANCODE_KP_BINARY = 218,
SDL_SCANCODE_KP_OCTAL = 219,
SDL_SCANCODE_KP_DECIMAL = 220,
SDL_SCANCODE_KP_HEXADECIMAL = 221,
SDL_SCANCODE_LCTRL = 224,
SDL_SCANCODE_LSHIFT = 225,
SDL_SCANCODE_LALT = 226, /**< alt, option */
SDL_SCANCODE_LGUI = 227, /**< windows, command (apple), meta */
SDL_SCANCODE_RCTRL = 228,
SDL_SCANCODE_RSHIFT = 229,
SDL_SCANCODE_RALT = 230, /**< alt gr, option */
SDL_SCANCODE_RGUI = 231, /**< windows, command (apple), meta */
SDL_SCANCODE_MODE = 257, /**< I'm not sure if this is really not covered
* by any of the above, but since there's a
* special SDL_KMOD_MODE for it I'm adding it here
*/
/* @} *//* Usage page 0x07 */
/**
* \name Usage page 0x0C
*
* These values are mapped from usage page 0x0C (USB consumer page).
* See https://usb.org/sites/default/files/hut1_2.pdf
*
* There are way more keys in the spec than we can represent in the
* current scancode range, so pick the ones that commonly come up in
* real world usage.
*/
/* @{ */
SDL_SCANCODE_AUDIONEXT = 258,
SDL_SCANCODE_AUDIOPREV = 259,
SDL_SCANCODE_AUDIOSTOP = 260,
SDL_SCANCODE_AUDIOPLAY = 261,
SDL_SCANCODE_AUDIOMUTE = 262,
SDL_SCANCODE_MEDIASELECT = 263,
SDL_SCANCODE_WWW = 264, /**< AL Internet Browser */
SDL_SCANCODE_MAIL = 265,
SDL_SCANCODE_CALCULATOR = 266, /**< AL Calculator */
SDL_SCANCODE_COMPUTER = 267,
SDL_SCANCODE_AC_SEARCH = 268, /**< AC Search */
SDL_SCANCODE_AC_HOME = 269, /**< AC Home */
SDL_SCANCODE_AC_BACK = 270, /**< AC Back */
SDL_SCANCODE_AC_FORWARD = 271, /**< AC Forward */
SDL_SCANCODE_AC_STOP = 272, /**< AC Stop */
SDL_SCANCODE_AC_REFRESH = 273, /**< AC Refresh */
SDL_SCANCODE_AC_BOOKMARKS = 274, /**< AC Bookmarks */
/* @} *//* Usage page 0x0C */
/**
* \name Walther keys
*
* These are values that Christian Walther added (for mac keyboard?).
*/
/* @{ */
SDL_SCANCODE_BRIGHTNESSDOWN = 275,
SDL_SCANCODE_BRIGHTNESSUP = 276,
SDL_SCANCODE_DISPLAYSWITCH = 277, /**< display mirroring/dual display
switch, video mode switch */
SDL_SCANCODE_KBDILLUMTOGGLE = 278,
SDL_SCANCODE_KBDILLUMDOWN = 279,
SDL_SCANCODE_KBDILLUMUP = 280,
SDL_SCANCODE_EJECT = 281,
SDL_SCANCODE_SLEEP = 282, /**< SC System Sleep */
SDL_SCANCODE_APP1 = 283,
SDL_SCANCODE_APP2 = 284,
/* @} *//* Walther keys */
/**
* \name Usage page 0x0C (additional media keys)
*
* These values are mapped from usage page 0x0C (USB consumer page).
*/
/* @{ */
SDL_SCANCODE_AUDIOREWIND = 285,
SDL_SCANCODE_AUDIOFASTFORWARD = 286,
/* @} *//* Usage page 0x0C (additional media keys) */
/**
* \name Mobile keys
*
* These are values that are often used on mobile phones.
*/
/* @{ */
SDL_SCANCODE_SOFTLEFT = 287, /**< Usually situated below the display on phones and
used as a multi-function feature key for selecting
a software defined function shown on the bottom left
of the display. */
SDL_SCANCODE_SOFTRIGHT = 288, /**< Usually situated below the display on phones and
used as a multi-function feature key for selecting
a software defined function shown on the bottom right
of the display. */
SDL_SCANCODE_CALL = 289, /**< Used for accepting phone calls. */
SDL_SCANCODE_ENDCALL = 290, /**< Used for rejecting phone calls. */
/* @} *//* Mobile keys */
/* Add any other keys here. */
SDL_NUM_SCANCODES = 512 /**< not a key, just marks the number of scancodes
for array bounds */
} SDL_Scancode;
#endif /* SDL_scancode_h_ */

2583
apps/agnes/src/agnes.c Normal file

File diff suppressed because it is too large Load diff

88
apps/agnes/src/agnes.h Normal file
View file

@ -0,0 +1,88 @@
#include <zeptolibc/zeptolibc.h>
/*
SPDX-License-Identifier: MIT
agnes
https://http://github.com/kgabis/agnes
Copyright (c) 2022 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef agnes_h
#define agnes_h
#ifdef __cplusplus
extern "C"
{
#endif
#define AGNES_VERSION_MAJOR 0
#define AGNES_VERSION_MINOR 2
#define AGNES_VERSION_PATCH 0
#define AGNES_VERSION_STRING "0.2.0"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
enum {
AGNES_SCREEN_WIDTH = 256,
AGNES_SCREEN_HEIGHT = 240
};
typedef struct {
bool a;
bool b;
bool select;
bool start;
bool up;
bool down;
bool left;
bool right;
} agnes_input_t;
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
} agnes_color_t;
typedef struct agnes agnes_t;
typedef struct agnes_state agnes_state_t;
agnes_t* agnes_make(void);
void agnes_destroy(agnes_t *agn);
bool agnes_load_ines_data(agnes_t *agnes, const void *data, size_t data_size);
void agnes_set_input(agnes_t *agnes, const agnes_input_t *input_1, const agnes_input_t *input_2);
size_t agnes_state_size(void);
void agnes_dump_state(const agnes_t *agnes, agnes_state_t *out_res);
bool agnes_restore_state(agnes_t *agnes, const agnes_state_t *state);
bool agnes_tick(agnes_t *agnes, bool *out_new_frame);
bool agnes_next_frame(agnes_t *agnes);
agnes_color_t agnes_get_screen_pixel(const agnes_t *agnes, int x, int y);
#ifdef __cplusplus
}
#endif
#endif /* agnes_h */

View file

@ -0,0 +1,49 @@
const std = @import("std");
extern fn console_write(data: [*]const u8, len: usize) void;
var wbuf:[4096]u8 = undefined;
var cw = ConsoleWriter.init(&wbuf);
const uvm = @import("uvm.zig");
pub const WriteError = error{ Unsupported, NotConnected };
pub const ConsoleWriter = struct {
interface: std.Io.Writer,
err: ?WriteError = null,
fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
var ret: usize = 0;
const b = w.buffered();
uvm.print(b);
_ = w.consume(b.len);
for (data) |d| {
uvm.print(d);
ret += d.len;
}
const pattern = data[data.len - 1];
for (0..splat) |_| {
uvm.print(pattern);
ret += pattern.len;
}
return ret;
}
pub fn init(buf: []u8) ConsoleWriter {
return ConsoleWriter{
.interface = .{
.buffer = buf,
.vtable = &.{
.drain = drain,
},
},
};
}
};
pub fn getWriter() *std.Io.Writer {
return &cw.interface;
}

BIN
apps/agnes/src/croom.nes Normal file

Binary file not shown.

103
apps/agnes/src/main.zig Normal file
View file

@ -0,0 +1,103 @@
const uvm = @import("uvm.zig");
const zeptolibc = @import("zeptolibc");
const std = @import("std");
const console = @import("console.zig").getWriter();
const sdlkeys = @cImport({
@cInclude("SDL_scancode.h");
});
const agnes = @cImport({
@cInclude("agnes.h");
});
var ag: ?*agnes.agnes_t = null;
var ag_input: agnes.agnes_input_t = undefined;
const romData = @embedFile("croom.nes");
const WIDTH = 256;
const HEIGHT = 240;
var gfxFramebuffer: [WIDTH * HEIGHT]u32 = undefined;
fn consoleWriteFn(data:[]const u8) void {
_ = console.print("{s}", .{data}) catch 0;
_ = console.flush() catch 0;
}
fn checkKeys() void {
var pressed:bool = undefined;
var scancode:u16 = undefined;
if (uvm.getkey(&scancode, &pressed)) {
if (pressed) {
switch(scancode) {
sdlkeys.SDL_SCANCODE_RIGHT => ag_input.right = true,
sdlkeys.SDL_SCANCODE_LEFT => ag_input.left = true,
sdlkeys.SDL_SCANCODE_UP => ag_input.up = true,
sdlkeys.SDL_SCANCODE_DOWN => ag_input.down = true,
sdlkeys.SDL_SCANCODE_Z => ag_input.a = true,
sdlkeys.SDL_SCANCODE_X => ag_input.b = true,
sdlkeys.SDL_SCANCODE_TAB => ag_input.select = true,
sdlkeys.SDL_SCANCODE_RETURN => ag_input.start = true,
else => {},
}
} else {
switch(scancode) {
sdlkeys.SDL_SCANCODE_RIGHT => ag_input.right = false,
sdlkeys.SDL_SCANCODE_LEFT => ag_input.left = false,
sdlkeys.SDL_SCANCODE_UP => ag_input.up = false,
sdlkeys.SDL_SCANCODE_DOWN => ag_input.down = false,
sdlkeys.SDL_SCANCODE_Z => ag_input.a = false,
sdlkeys.SDL_SCANCODE_X => ag_input.b = false,
sdlkeys.SDL_SCANCODE_TAB => ag_input.select = false,
sdlkeys.SDL_SCANCODE_RETURN => ag_input.start = false,
else => {},
}
}
}
agnes.agnes_set_input(ag, &ag_input, 0);
}
fn submain() !void {
// init zepto with a memory allocator and console writer
zeptolibc.init(uvm.allocator(), consoleWriteFn);
ag = agnes.agnes_make();
if (agnes.agnes_load_ines_data(ag, @ptrCast(romData), romData.len)) {
try console.print("load rom ok\n", .{});
} else {
try console.print("load rom failed\n", .{});
}
try console.flush();
agnes.agnes_set_input(ag, &ag_input, 0);
while(true) {
if (!agnes.agnes_next_frame(ag)) {
try console.print("Next frame failed!\n", .{});
try console.flush();
}
var i:usize = 0;
for (0..agnes.AGNES_SCREEN_HEIGHT) |y| {
for (0..agnes.AGNES_SCREEN_WIDTH) |x| {
const c = agnes.agnes_get_screen_pixel(ag, @intCast(x), @intCast(y));
const c_val = @as(u32, @intCast(0xFF)) << 24 | @as(u32, @intCast(c.b)) << 16 | @as(u32, @intCast(c.g)) << 8 | @as(u32, @intCast(c.r));
gfxFramebuffer[i] = c_val;
i+=1;
}
}
checkKeys();
uvm.render(@ptrCast(&gfxFramebuffer), WIDTH * HEIGHT * 4);
}
}
export fn main() void {
_ = submain() catch {
uvm.println("Caught err");
};
}

88
apps/agnes/src/uvm.zig Normal file
View file

@ -0,0 +1,88 @@
const uvm32 = @cImport({
@cDefine("USE_MAIN", "1");
@cInclude("uvm32_target.h");
});
const buildopts = @import("buildopts");
const std = @import("std");
const extram:[*]u8 = @ptrFromInt(uvm32.UVM32_EXTRAM_BASE);
const extram_len = buildopts.heapsize;
var fba:std.heap.FixedBufferAllocator = .init(extram[0..extram_len]);
pub fn allocator() std.mem.Allocator {
return fba.allocator();
}
pub inline fn syscall(id: u32, param1: u32, param2: u32) u32 {
var val: u32 = undefined;
asm volatile ("ecall"
: [val] "={a2}" (val),
: [param1] "{a0}" (param1), [param2] "{a1}" (param2),
[id] "{a7}" (id),
: .{ .memory = true });
return val;
}
pub inline fn renderAudio(audbuf: [*]const i16, len:u32) void {
_ = syscall(uvm32.UVM32_SYSCALL_RENDERAUDIO, @intFromPtr(audbuf), len);
}
pub inline fn render(fb: [*]const u8, len:u32) void {
_ = syscall(uvm32.UVM32_SYSCALL_RENDER, @intFromPtr(fb), len);
}
pub inline fn getc() ?u8 {
const key = syscall(uvm32.UVM32_SYSCALL_GETC, 0, 0);
if (key == 0xFFFFFFFF) {
return null;
} else {
return @truncate(key);
}
}
pub inline fn getkey(code: *u16, pressed:*bool) bool {
const k = syscall(uvm32.UVM32_SYSCALL_GETKEY, 0, 0);
if (k == 0xFFFFFFFF) {
return false;
} else {
code.* = @truncate(k & 0xFFFF);
pressed.* = (k & 0x80000000) != 0;
return true;
}
}
pub inline fn millis() u32 {
return syscall(uvm32.UVM32_SYSCALL_MILLIS, 0, 0);
}
// dupeZ would be better, but want to avoid using an allocator
// this is of course, unsafe...
var termination_buf:[512]u8 = undefined;
pub inline fn print(m: []const u8) void {
@memcpy(termination_buf[0..m.len], m);
termination_buf[m.len] = 0;
const s = termination_buf[0..m.len :0];
_ = syscall(uvm32.UVM32_SYSCALL_PRINT, @intFromPtr(s.ptr), 0);
}
pub inline fn println(m: []const u8) void {
@memcpy(termination_buf[0..m.len], m);
termination_buf[m.len] = 0;
const s = termination_buf[0..m.len :0];
_ = syscall(uvm32.UVM32_SYSCALL_PRINTLN, @intFromPtr(s.ptr), 0);
}
pub inline fn yield() void {
_ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0, 0);
}
pub inline fn halt() void {
_ = syscall(uvm32.UVM32_SYSCALL_HALT, 0, 0);
}
pub inline fn putc(c:u8) void {
_ = syscall(uvm32.UVM32_SYSCALL_PUTC, c, 0);
}