aboutsummaryrefslogtreecommitdiff
path: root/src/drv
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-07-07 13:22:53 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-11-11 00:08:15 +0100
commit7861a52adf92a083bb2aed4c35f98d8035dce032 (patch)
tree28cd3c40e4c878f730f5df3c1d93bdf91af490c3 /src/drv
parent7fc48e9216ff809da5f8055a50b0be17628ef1df (diff)
downloadwnix-7861a52adf92a083bb2aed4c35f98d8035dce032.tar.gz
Setup project skeleton
Diffstat (limited to 'src/drv')
-rw-r--r--src/drv/CMakeLists.txt28
-rw-r--r--src/drv/event/CMakeLists.txt18
-rw-r--r--src/drv/event/include/drv/event.h49
-rw-r--r--src/drv/include/drv/drv.h28
-rw-r--r--src/drv/include/drv/time.h28
-rw-r--r--src/drv/private_include/drv/port.h28
-rw-r--r--src/drv/private_include/drv/tree.h31
-rw-r--r--src/drv/private_include/drv/types.h30
-rw-r--r--src/drv/ps1/CMakeLists.txt37
-rw-r--r--src/drv/ps1/bios/CMakeLists.txt19
-rw-r--r--src/drv/ps1/bios/include/drv/ps1/bios.h128
-rw-r--r--src/drv/ps1/bios/src/CMakeLists.txt38
-rw-r--r--src/drv/ps1/bios/src/CdAsyncGetStatus.s21
-rw-r--r--src/drv/ps1/bios/src/CdAsyncReadSector.s21
-rw-r--r--src/drv/ps1/bios/src/CdAsyncSeekL.s21
-rw-r--r--src/drv/ps1/bios/src/CdInit.s21
-rw-r--r--src/drv/ps1/bios/src/CdRemove.s21
-rw-r--r--src/drv/ps1/bios/src/CloseEvent.s21
-rw-r--r--src/drv/ps1/bios/src/DisableEvent.s21
-rw-r--r--src/drv/ps1/bios/src/EnableEvent.s23
-rw-r--r--src/drv/ps1/bios/src/EnterCriticalSection.s25
-rw-r--r--src/drv/ps1/bios/src/ExitCriticalSection.s23
-rw-r--r--src/drv/ps1/bios/src/GetConf.s21
-rw-r--r--src/drv/ps1/bios/src/OpenEvent.s21
-rw-r--r--src/drv/ps1/bios/src/Printf.s21
-rw-r--r--src/drv/ps1/bios/src/RestoreState.s21
-rw-r--r--src/drv/ps1/bios/src/ReturnFromException.s21
-rw-r--r--src/drv/ps1/bios/src/SaveState.s21
-rw-r--r--src/drv/ps1/bios/src/SetConf.s21
-rw-r--r--src/drv/ps1/bios/src/SetCustomExitFromException.s21
-rw-r--r--src/drv/ps1/bios/src/TestEvent.s23
-rw-r--r--src/drv/ps1/bios/src/WaitEvent.s23
-rw-r--r--src/drv/ps1/cd/CMakeLists.txt27
-rw-r--r--src/drv/ps1/cd/include/drv/ps1/cd.h28
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h66
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h37
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/types.h111
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h36
-rw-r--r--src/drv/ps1/cd/src/CMakeLists.txt33
-rw-r--r--src/drv/ps1/cd/src/ensure_event.c37
-rw-r--r--src/drv/ps1/cd/src/free.c23
-rw-r--r--src/drv/ps1/cd/src/getstat.c70
-rw-r--r--src/drv/ps1/cd/src/init.c42
-rw-r--r--src/drv/ps1/cd/src/next.c37
-rw-r--r--src/drv/ps1/cd/src/prv.c22
-rw-r--r--src/drv/ps1/cd/src/read.c239
-rw-r--r--src/drv/ps1/cd/src/readdebug253
-rw-r--r--src/drv/ps1/cd/src/send.c101
-rw-r--r--src/drv/ps1/cd/src/toseekl.c54
-rw-r--r--src/drv/ps1/cd/src/update.c47
-rw-r--r--src/drv/ps1/cd/src/virt/CMakeLists.txt25
-rw-r--r--src/drv/ps1/cd/src/virt/init.c41
-rw-r--r--src/drv/ps1/cd/src/write.c31
-rw-r--r--src/drv/ps1/cpu/CMakeLists.txt18
-rw-r--r--src/drv/ps1/cpu/include/drv/ps1/cpu.h24
-rw-r--r--src/drv/ps1/dma/CMakeLists.txt18
-rw-r--r--src/drv/ps1/dma/include/drv/ps1/dma.h97
-rw-r--r--src/drv/ps1/event/CMakeLists.txt20
-rw-r--r--src/drv/ps1/event/include/drv/ps1/event.h31
-rw-r--r--src/drv/ps1/event/src/CMakeLists.txt23
-rw-r--r--src/drv/ps1/event/src/close.c25
-rw-r--r--src/drv/ps1/event/src/disable.c25
-rw-r--r--src/drv/ps1/event/src/enable.c25
-rw-r--r--src/drv/ps1/event/src/open.c31
-rw-r--r--src/drv/ps1/event/src/test.c28
-rw-r--r--src/drv/ps1/gpu/CMakeLists.txt18
-rw-r--r--src/drv/ps1/gpu/include/drv/ps1/gpu.h173
-rw-r--r--src/drv/ps1/include/drv/ps1.h28
-rw-r--r--src/drv/ps1/irq/CMakeLists.txt20
-rw-r--r--src/drv/ps1/irq/include/drv/ps1/irq.h64
-rw-r--r--src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h24
-rw-r--r--src/drv/ps1/irq/private_include/drv/ps1/irq/types.h26
-rw-r--r--src/drv/ps1/irq/src/CMakeLists.txt22
-rw-r--r--src/drv/ps1/irq/src/handler.c32
-rw-r--r--src/drv/ps1/irq/src/head.c22
-rw-r--r--src/drv/ps1/irq/src/init.c40
-rw-r--r--src/drv/ps1/irq/src/set.c36
-rw-r--r--src/drv/ps1/mc/CMakeLists.txt20
-rw-r--r--src/drv/ps1/mc/include/drv/ps1/mc.h28
-rw-r--r--src/drv/ps1/mc/private_include/drv/ps1/mc/types.h37
-rw-r--r--src/drv/ps1/mc/src/CMakeLists.txt21
-rw-r--r--src/drv/ps1/mc/src/free.c23
-rw-r--r--src/drv/ps1/mc/src/init.c34
-rw-r--r--src/drv/ps1/mc/src/update.c26
-rw-r--r--src/drv/ps1/pad/CMakeLists.txt20
-rw-r--r--src/drv/ps1/pad/include/drv/ps1/pad.h28
-rw-r--r--src/drv/ps1/pad/private_include/drv/ps1/pad/types.h29
-rw-r--r--src/drv/ps1/pad/src/CMakeLists.txt21
-rw-r--r--src/drv/ps1/pad/src/free.c23
-rw-r--r--src/drv/ps1/pad/src/init.c34
-rw-r--r--src/drv/ps1/pad/src/update.c26
-rw-r--r--src/drv/ps1/private_include/drv/ps1/types.h35
-rw-r--r--src/drv/ps1/rcnt/CMakeLists.txt22
-rw-r--r--src/drv/ps1/rcnt/include/drv/ps1/rcnt.h45
-rw-r--r--src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h36
-rw-r--r--src/drv/ps1/rcnt/src/CMakeLists.txt19
-rw-r--r--src/drv/ps1/rcnt/src/init.c62
-rw-r--r--src/drv/ps1/sio/CMakeLists.txt22
-rw-r--r--src/drv/ps1/sio/include/drv/ps1/sio.h28
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h31
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h136
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h27
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/types.h65
-rw-r--r--src/drv/ps1/sio/src/CMakeLists.txt29
-rw-r--r--src/drv/ps1/sio/src/free.c23
-rw-r--r--src/drv/ps1/sio/src/globals.c21
-rw-r--r--src/drv/ps1/sio/src/init.c70
-rw-r--r--src/drv/ps1/sio/src/irq.c71
-rw-r--r--src/drv/ps1/sio/src/next.c34
-rw-r--r--src/drv/ps1/sio/src/read.c125
-rw-r--r--src/drv/ps1/sio/src/read_nb.c61
-rw-r--r--src/drv/ps1/sio/src/update.c98
-rw-r--r--src/drv/ps1/sio/src/write.c117
-rw-r--r--src/drv/ps1/src/CMakeLists.txt21
-rw-r--r--src/drv/ps1/src/free.c32
-rw-r--r--src/drv/ps1/src/init.c59
-rw-r--r--src/drv/ps1/src/update.c35
-rw-r--r--src/drv/ps1/time/CMakeLists.txt22
-rw-r--r--src/drv/ps1/time/include/drv/ps1/time.h24
-rw-r--r--src/drv/ps1/time/private_include/drv/ps1/time/types.h26
-rw-r--r--src/drv/ps1/time/src/CMakeLists.txt23
-rw-r--r--src/drv/ps1/time/src/getres.c34
-rw-r--r--src/drv/ps1/time/src/gettime.c38
-rw-r--r--src/drv/ps1/time/src/globals.c22
-rw-r--r--src/drv/ps1/time/src/settime.c37
-rw-r--r--src/drv/ps1/time/src/tick.c42
-rw-r--r--src/drv/src/CMakeLists.txt22
-rw-r--r--src/drv/src/free.c31
-rw-r--r--src/drv/src/init.c62
-rw-r--r--src/drv/src/tree.c51
-rw-r--r--src/drv/src/update.c32
-rw-r--r--src/drv/tty/CMakeLists.txt20
-rw-r--r--src/drv/tty/include/drv/tty.h28
-rw-r--r--src/drv/tty/private_include/drv/tty/font.h29
-rw-r--r--src/drv/tty/private_include/drv/tty/ops.h30
-rw-r--r--src/drv/tty/private_include/drv/tty/types.h40
-rw-r--r--src/drv/tty/src/CMakeLists.txt27
-rw-r--r--src/drv/tty/src/free.c39
-rw-r--r--src/drv/tty/src/init.c58
-rw-r--r--src/drv/tty/src/ps1/CMakeLists.txt19
-rw-r--r--src/drv/tty/src/ps1/ttyfont_tim.c801
-rw-r--r--src/drv/tty/src/setdim.c62
-rw-r--r--src/drv/tty/src/update.backup.c125
-rw-r--r--src/drv/tty/src/update.c126
-rw-r--r--src/drv/tty/src/write.c70
145 files changed, 6758 insertions, 0 deletions
diff --git a/src/drv/CMakeLists.txt b/src/drv/CMakeLists.txt
new file mode 100644
index 0000000..3306d93
--- /dev/null
+++ b/src/drv/CMakeLists.txt
@@ -0,0 +1,28 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv)
+add_subdirectory(event)
+add_subdirectory(tty)
+add_subdirectory(src)
+target_include_directories(drv PUBLIC include PRIVATE private_include)
+target_link_libraries(drv PUBLIC drv_event PRIVATE drv_tty)
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+ target_compile_definitions(drv PRIVATE DRV_PS1)
+ target_link_libraries(drv PUBLIC drv_ps1_time PRIVATE drv_ps1)
+endif()
diff --git a/src/drv/event/CMakeLists.txt b/src/drv/event/CMakeLists.txt
new file mode 100644
index 0000000..7d52511
--- /dev/null
+++ b/src/drv/event/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_event INTERFACE)
+target_include_directories(drv_event INTERFACE include)
diff --git a/src/drv/event/include/drv/event.h b/src/drv/event/include/drv/event.h
new file mode 100644
index 0000000..5707242
--- /dev/null
+++ b/src/drv/event/include/drv/event.h
@@ -0,0 +1,49 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_EVENT_H
+#define DRV_EVENT_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct drv_event_done
+{
+ int (*f)(int error, void *args);
+ void *args;
+};
+
+struct drv_event_ops
+{
+ int (*read)(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+ int (*read_nb)(void *buf, size_t n, void *args);
+ int (*write)(const void *buf, size_t n, const struct drv_event_done *done,
+ void *args);
+ void *args;
+};
+
+struct drv_event
+{
+ int (*status)(const char *node, const struct drv_event_ops *ops,
+ bool available, mode_t mode, void *args);
+ void *args;
+};
+
+#endif
diff --git a/src/drv/include/drv/drv.h b/src/drv/include/drv/drv.h
new file mode 100644
index 0000000..eb8bee0
--- /dev/null
+++ b/src/drv/include/drv/drv.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_H
+#define DRV_H
+
+#include <drv/event.h>
+
+struct drv *drv_init(const struct drv_event *ev);
+int drv_update(struct drv *d);
+void drv_free(struct drv *d);
+
+#endif
diff --git a/src/drv/include/drv/time.h b/src/drv/include/drv/time.h
new file mode 100644
index 0000000..12b213d
--- /dev/null
+++ b/src/drv/include/drv/time.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TIME_H
+#define DRV_TIME_H
+
+#include <time.h>
+
+int drv_time_getres(clockid_t id, struct timespec *ts);
+int drv_time_gettime(clockid_t id, struct timespec *ts);
+int drv_time_settime(clockid_t id, const struct timespec *ts);
+
+#endif
diff --git a/src/drv/private_include/drv/port.h b/src/drv/private_include/drv/port.h
new file mode 100644
index 0000000..cdf30ab
--- /dev/null
+++ b/src/drv/private_include/drv/port.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PORT_H
+#define DRV_PORT_H
+
+struct drv_port;
+
+#ifdef DRV_PS1
+#include <drv/ps1.h>
+#endif
+
+#endif
diff --git a/src/drv/private_include/drv/tree.h b/src/drv/private_include/drv/tree.h
new file mode 100644
index 0000000..da4b7e9
--- /dev/null
+++ b/src/drv/private_include/drv/tree.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TREE_H
+#define DRV_TREE_H
+
+#include <drv/drv.h>
+#include <drv/port.h>
+#include <stddef.h>
+
+extern struct drv_port *(*const drv_tree_init[])(const struct drv_event *);
+extern int (*const drv_tree_update[])(struct drv_port *);
+extern void (*const drv_tree_free[])(struct drv_port *);
+extern const size_t drv_tree_n;
+
+#endif
diff --git a/src/drv/private_include/drv/types.h b/src/drv/private_include/drv/types.h
new file mode 100644
index 0000000..959e12d
--- /dev/null
+++ b/src/drv/private_include/drv/types.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TYPES_H
+#define DRV_TYPES_H
+
+#include <stddef.h>
+
+struct drv
+{
+ struct drv_port **ports;
+ size_t n;
+};
+
+#endif
diff --git a/src/drv/ps1/CMakeLists.txt b/src/drv/ps1/CMakeLists.txt
new file mode 100644
index 0000000..08d97c2
--- /dev/null
+++ b/src/drv/ps1/CMakeLists.txt
@@ -0,0 +1,37 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(bios)
+add_subdirectory(cd)
+add_subdirectory(cpu)
+add_subdirectory(dma)
+add_subdirectory(event)
+add_subdirectory(gpu)
+add_subdirectory(irq)
+add_subdirectory(mc)
+add_subdirectory(pad)
+add_subdirectory(rcnt)
+add_subdirectory(sio)
+add_subdirectory(time)
+add_library(drv_ps1)
+add_subdirectory(src)
+target_include_directories(drv_ps1 PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1 PUBLIC c drv_event PRIVATE
+ drv_ps1_cd
+ drv_ps1_mc
+ drv_ps1_pad
+ drv_ps1_sio
+)
diff --git a/src/drv/ps1/bios/CMakeLists.txt b/src/drv/ps1/bios/CMakeLists.txt
new file mode 100644
index 0000000..ebc0937
--- /dev/null
+++ b/src/drv/ps1/bios/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_bios)
+add_subdirectory(src)
+target_include_directories(drv_ps1_bios INTERFACE include)
diff --git a/src/drv/ps1/bios/include/drv/ps1/bios.h b/src/drv/ps1/bios/include/drv/ps1/bios.h
new file mode 100644
index 0000000..ca53194
--- /dev/null
+++ b/src/drv/ps1/bios/include/drv/ps1/bios.h
@@ -0,0 +1,128 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PS1_BIOS_H
+#define PS1_BIOS_H
+
+#include <stdint.h>
+#include <setjmp.h>
+
+#if __GNUC__
+#define PRINTF_ATTR __attribute__ ((format (__printf__, 1, 2)))
+#else
+#define PRINTF_ATTR
+#endif
+
+enum
+{
+ CLASS_IRQ0 = (long)0xf0000001,
+ CLASS_GPU,
+ CLASS_CDROM,
+ CLASS_DMA,
+ CLASS_RTC0 = (long)0xf2000000,
+ CLASS_RTC1,
+ CLASS_RTC2,
+ CLASS_VBLANK,
+ CLASS_CONTROLLER = (long)0xf0000008,
+ CLASS_SPU,
+ CLASS_PIO,
+ CLASS_SIO
+};
+
+enum
+{
+ MODE_EXECUTE = 0x1000,
+ MODE_READY = 0x2000
+};
+
+enum
+{
+ SPEC_COUNTER_ZERO = 1,
+ SPEC_INTERRUPTED = 1 << 1,
+ SPEC_EOF = 1 << 2,
+ SPEC_FILE_CLOSED = 1 << 3,
+ SPEC_COMMAND_ACK = 1 << 4,
+ SPEC_COMMAND_COMPLETE = 1 << 5,
+ SPEC_DATA_READY = 1 << 6,
+ SPEC_DATA_END = 1 << 7,
+ SPEC_TIMEOUT = 1 << 8,
+ SPEC_UNKNOWN_CMD = 1 << 9,
+ SPEC_END_READ_BUF = 1 << 10,
+ SPEC_END_WRITE_BUF = 1 << 11,
+ SPEC_GENERAL_INTERRUPT = 1 << 12,
+ SPEC_NEW_DEVICE = 1 << 13,
+ SPEC_SYSCALL = 1 << 14,
+ SPEC_ERROR = 1 << 15,
+ SPEC_WRITE_ERROR,
+ SPEC_DOMAIN_ERROR = 0x301,
+ SPEC_RANGE_RNG
+};
+
+struct CdAsyncSeekL
+{
+ uint8_t minutes, seconds, frames;
+};
+
+union SetMode
+{
+ struct
+ {
+ uint8_t cdda :1, autopause :1, report :1, xa_filter :1, ignore :1,
+ whole_sector :1, xa_adpcm :1, speed :1;
+ } bits;
+
+ uint8_t mask;
+};
+
+struct CdAsyncReadSector_mode
+{
+ union SetMode mode;
+ union
+ {
+ struct
+ {
+ uint8_t reads :1, :7;
+ } bits;
+ } read;
+
+ uint16_t reserved;
+};
+
+int EnterCriticalSection(void);
+void ExitCriticalSection(void);
+void GetConf(uint32_t *events, uint32_t *tcb, void **stacktop);
+void SetConf(uint32_t events, uint32_t tcb, void *stacktop);
+int OpenEvent(int class, int spec, int mode, int (*f)(void));
+int EnableEvent(int event);
+int DisableEvent(int event);
+int CloseEvent(int event);
+int TestEvent(int event);
+int WaitEvent(int event);
+int CdAsyncGetStatus(uint8_t *response);
+int CdAsyncReadSector(unsigned count, void *dst,
+ struct CdAsyncReadSector_mode mode);
+int CdAsyncSeekL(const struct CdAsyncSeekL *seekl);
+int Printf(const char *fmt, ...) PRINTF_ATTR;
+void SetCustomExitFromException(jmp_buf jmp);
+void CdInit(void);
+void CdRemove(void);
+int SaveState(jmp_buf buf);
+void RestoreState(jmp_buf buf, int value);
+void ReturnFromException(void);
+
+#endif
diff --git a/src/drv/ps1/bios/src/CMakeLists.txt b/src/drv/ps1/bios/src/CMakeLists.txt
new file mode 100644
index 0000000..67ea62b
--- /dev/null
+++ b/src/drv/ps1/bios/src/CMakeLists.txt
@@ -0,0 +1,38 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_bios PRIVATE
+ CdAsyncGetStatus.s
+ CdAsyncReadSector.s
+ CdAsyncSeekL.s
+ CdInit.s
+ CdRemove.s
+ CloseEvent.s
+ DisableEvent.s
+ EnableEvent.s
+ EnterCriticalSection.s
+ ExitCriticalSection.s
+ GetConf.s
+ OpenEvent.s
+ Printf.s
+ RestoreState.s
+ ReturnFromException.s
+ SaveState.s
+ SetConf.s
+ SetCustomExitFromException.s
+ TestEvent.s
+ WaitEvent.s
+)
diff --git a/src/drv/ps1/bios/src/CdAsyncGetStatus.s b/src/drv/ps1/bios/src/CdAsyncGetStatus.s
new file mode 100644
index 0000000..18922da
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdAsyncGetStatus.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdAsyncGetStatus
+
+CdAsyncGetStatus:
+ li $9, 0x7c
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdAsyncReadSector.s b/src/drv/ps1/bios/src/CdAsyncReadSector.s
new file mode 100644
index 0000000..6411e12
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdAsyncReadSector.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdAsyncReadSector
+
+CdAsyncReadSector:
+ li $9, 0x7e
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdAsyncSeekL.s b/src/drv/ps1/bios/src/CdAsyncSeekL.s
new file mode 100644
index 0000000..529d116
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdAsyncSeekL.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdAsyncSeekL
+
+CdAsyncSeekL:
+ li $9, 0x78
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdInit.s b/src/drv/ps1/bios/src/CdInit.s
new file mode 100644
index 0000000..dcf3474
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdInit.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdInit
+
+CdInit:
+ li $9, 0x54
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdRemove.s b/src/drv/ps1/bios/src/CdRemove.s
new file mode 100644
index 0000000..e3bb34d
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdRemove.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdRemove
+
+CdRemove:
+ li $9, 0x56
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CloseEvent.s b/src/drv/ps1/bios/src/CloseEvent.s
new file mode 100644
index 0000000..7dd47e3
--- /dev/null
+++ b/src/drv/ps1/bios/src/CloseEvent.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CloseEvent
+
+CloseEvent:
+ li $9, 0x9
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/DisableEvent.s b/src/drv/ps1/bios/src/DisableEvent.s
new file mode 100644
index 0000000..f32dcf8
--- /dev/null
+++ b/src/drv/ps1/bios/src/DisableEvent.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global DisableEvent
+
+DisableEvent:
+ li $9, 0xd
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/EnableEvent.s b/src/drv/ps1/bios/src/EnableEvent.s
new file mode 100644
index 0000000..f6da29d
--- /dev/null
+++ b/src/drv/ps1/bios/src/EnableEvent.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global EnableEvent
+
+EnableEvent:
+ li $9, 0xc
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/EnterCriticalSection.s b/src/drv/ps1/bios/src/EnterCriticalSection.s
new file mode 100644
index 0000000..c8302e0
--- /dev/null
+++ b/src/drv/ps1/bios/src/EnterCriticalSection.s
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global EnterCriticalSection
+
+EnterCriticalSection:
+ li $a0, 1
+ syscall
+ nop
+ jr $ra
+ nop
diff --git a/src/drv/ps1/bios/src/ExitCriticalSection.s b/src/drv/ps1/bios/src/ExitCriticalSection.s
new file mode 100644
index 0000000..198b040
--- /dev/null
+++ b/src/drv/ps1/bios/src/ExitCriticalSection.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global ExitCriticalSection
+
+ExitCriticalSection:
+ li $a0, 2
+ syscall
+ nop
+ jr $ra
+ nop
diff --git a/src/drv/ps1/bios/src/GetConf.s b/src/drv/ps1/bios/src/GetConf.s
new file mode 100644
index 0000000..927b950
--- /dev/null
+++ b/src/drv/ps1/bios/src/GetConf.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global GetConf
+
+GetConf:
+ li $9, 0x9d
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/OpenEvent.s b/src/drv/ps1/bios/src/OpenEvent.s
new file mode 100644
index 0000000..dca7141
--- /dev/null
+++ b/src/drv/ps1/bios/src/OpenEvent.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global OpenEvent
+
+OpenEvent:
+ li $9, 0x8
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/Printf.s b/src/drv/ps1/bios/src/Printf.s
new file mode 100644
index 0000000..9e0a77f
--- /dev/null
+++ b/src/drv/ps1/bios/src/Printf.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global Printf
+
+Printf:
+ li $9, 0x3f
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/RestoreState.s b/src/drv/ps1/bios/src/RestoreState.s
new file mode 100644
index 0000000..c830296
--- /dev/null
+++ b/src/drv/ps1/bios/src/RestoreState.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global RestoreState
+
+RestoreState:
+ li $9, 0x14
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/ReturnFromException.s b/src/drv/ps1/bios/src/ReturnFromException.s
new file mode 100644
index 0000000..6af3bb3
--- /dev/null
+++ b/src/drv/ps1/bios/src/ReturnFromException.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global ReturnFromException
+
+ReturnFromException:
+ li $9, 0x17
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/SaveState.s b/src/drv/ps1/bios/src/SaveState.s
new file mode 100644
index 0000000..eb72ea3
--- /dev/null
+++ b/src/drv/ps1/bios/src/SaveState.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global SaveState
+
+SaveState:
+ li $9, 0x13
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/SetConf.s b/src/drv/ps1/bios/src/SetConf.s
new file mode 100644
index 0000000..5063667
--- /dev/null
+++ b/src/drv/ps1/bios/src/SetConf.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global SetConf
+
+SetConf:
+ li $9, 0x9c
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/SetCustomExitFromException.s b/src/drv/ps1/bios/src/SetCustomExitFromException.s
new file mode 100644
index 0000000..75cf8cc
--- /dev/null
+++ b/src/drv/ps1/bios/src/SetCustomExitFromException.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global SetCustomExitFromException
+
+SetCustomExitFromException:
+ li $9, 0x19
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/TestEvent.s b/src/drv/ps1/bios/src/TestEvent.s
new file mode 100644
index 0000000..af0edab
--- /dev/null
+++ b/src/drv/ps1/bios/src/TestEvent.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global TestEvent
+
+TestEvent:
+ li $9, 0xb
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/WaitEvent.s b/src/drv/ps1/bios/src/WaitEvent.s
new file mode 100644
index 0000000..8f58d52
--- /dev/null
+++ b/src/drv/ps1/bios/src/WaitEvent.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global WaitEvent
+
+WaitEvent:
+ li $9, 0xa
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/cd/CMakeLists.txt b/src/drv/ps1/cd/CMakeLists.txt
new file mode 100644
index 0000000..9b84541
--- /dev/null
+++ b/src/drv/ps1/cd/CMakeLists.txt
@@ -0,0 +1,27 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_cd)
+add_subdirectory(src)
+target_include_directories(drv_ps1_cd PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_cd
+ PUBLIC
+ c
+ drv_event
+ PRIVATE
+ drv_ps1_bios
+ drv_ps1_event
+)
diff --git a/src/drv/ps1/cd/include/drv/ps1/cd.h b/src/drv/ps1/cd/include/drv/ps1/cd.h
new file mode 100644
index 0000000..ff57622
--- /dev/null
+++ b/src/drv/ps1/cd/include/drv/ps1/cd.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_H
+#define DRV_PS1_CD_H
+
+#include <drv/event.h>
+
+struct drv_ps1_cd *drv_ps1_cd_init(const struct drv_event *ev);
+int drv_ps1_cd_update(struct drv_ps1_cd *cd);
+void drv_ps1_cd_free(struct drv_ps1_cd *cd);
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h
new file mode 100644
index 0000000..37b2d03
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h
@@ -0,0 +1,66 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_REGS_H
+#define DRV_PS1_CD_REGS_H
+
+#include <stdint.h>
+
+struct cd_reg_status
+{
+ uint8_t index :2;
+ const uint8_t ADPBUSY :1, PRMEMPT :1, PRMWRDY :1, RSLRRDY :1, DRQSTS :1,
+ BUSYSTS :1;
+};
+
+struct cd_reg_cmd
+{
+ uint8_t cmd;
+};
+
+struct cd_reg_rsp
+{
+ uint8_t rsp;
+};
+
+struct cd_reg_param
+{
+ uint8_t param;
+};
+
+union cd_reg_if
+{
+ const struct
+ {
+ uint8_t response :3, :1, cmd_start :1, :3;
+ } r;
+
+ struct
+ {
+ uint8_t ack: 5, :1, CLRPRM :1, :1;
+ } w;
+};
+
+#define CD_REG(x) (0x1f801800 + (x))
+#define CD_REG_STATUS ((volatile struct cd_reg_status *)CD_REG(0))
+#define CD_REG_CMD ((volatile struct cd_reg_cmd *)CD_REG(1))
+#define CD_REG_RSP ((const volatile struct cd_reg_rsp *)CD_REG(1))
+#define CD_REG_PARAM ((volatile struct cd_reg_param *)CD_REG(2))
+#define CD_REG_IF ((volatile union cd_reg_if *)CD_REG(3))
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
new file mode 100644
index 0000000..0b756de
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_ROUTINES_H
+#define DRV_PS1_CD_ROUTINES_H
+
+#include <drv/event.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/bios.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+int drv_ps1_cd_send(const struct cmd *cmd);
+int drv_ps1_cd_getstat(void);
+int drv_ps1_cd_read(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_cd_write(const void *buf, size_t n,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_cd_next(void);
+struct CdAsyncSeekL drv_ps1_cd_toseekl(unsigned i);
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/types.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/types.h
new file mode 100644
index 0000000..2d4ae51
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/types.h
@@ -0,0 +1,111 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_TYPES_H
+#define DRV_PS1_CD_TYPES_H
+
+#include <drv/event.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct drv_ps1_cd
+{
+ bool available;
+ struct drv_event ev;
+};
+
+struct cmd
+{
+ enum
+ {
+ CMD_SYNC,
+ CMD_GETSTAT,
+ CMD_SETLOC,
+ } cmd;
+
+ union cmd_param
+ {
+ struct cmd_setloc
+ {
+ uint8_t min, sec, sect;
+ } setloc;
+ } params;
+};
+
+struct cd_prv_getstat
+{
+ union
+ {
+ struct
+ {
+ uint8_t invalid :1, motor :1, seek_error :1, id_error :1,
+ shell_open :1, reading :1, seeking :1, playing_cdda :1;
+ } bits;
+
+ uint8_t byte;
+ } status;
+};
+
+struct cd_prv_read
+{
+ int endevent, errevent;
+};
+
+struct cd_req_read
+{
+ void *buf;
+ size_t n;
+ off_t offset;
+};
+
+struct cd_req
+{
+ union
+ {
+ struct cd_req_read read;
+ } u;
+
+ int (*f)(void);
+ struct drv_event_done done;
+ struct cd_req *next;
+};
+
+enum {CD_SECTOR_SZ = 2048};
+
+struct cd_prv
+{
+ bool available, sector_read;
+ int (*next)(void);
+ int event;
+ struct cmd cmd;
+ struct cd_req *head, *tail;
+ char sector[CD_SECTOR_SZ];
+ off_t offset;
+
+ union
+ {
+ struct cd_prv_getstat getstat;
+ struct cd_prv_read read;
+ } u;
+};
+
+extern struct cd_prv drv_ps1_cd_prv;
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h
new file mode 100644
index 0000000..59437c0
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_VIRT_TYPES_H
+#define DRV_PS1_CD_VIRT_TYPES_H
+
+#include <drv/event.h>
+
+struct drv_ps1_cd
+{
+ struct drv_event ev;
+};
+
+struct cd_prv
+{
+ int (*next)(void);
+};
+
+extern struct cd_prv drv_ps1_cd_prv;
+
+#endif
diff --git a/src/drv/ps1/cd/src/CMakeLists.txt b/src/drv/ps1/cd/src/CMakeLists.txt
new file mode 100644
index 0000000..df5ecca
--- /dev/null
+++ b/src/drv/ps1/cd/src/CMakeLists.txt
@@ -0,0 +1,33 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+if(WNIX_VIRT_CD)
+ add_subdirectory(virt)
+else()
+ target_sources(drv_ps1_cd PRIVATE
+ free.c
+ getstat.c
+ init.c
+ next.c
+ prv.c
+ read.c
+ toseekl.c
+ update.c
+ write.c
+ )
+endif()
+
+target_link_libraries(drv_ps1_cd PRIVATE kprintf)
diff --git a/src/drv/ps1/cd/src/ensure_event.c b/src/drv/ps1/cd/src/ensure_event.c
new file mode 100644
index 0000000..592184a
--- /dev/null
+++ b/src/drv/ps1/cd/src/ensure_event.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <stddef.h>
+
+int drv_ps1_cd_ensure_event(struct cd_prv *const p)
+{
+ if (p->event)
+ return 0;
+
+ const int event = drv_ps1_event_open(CLASS_CDROM, SPEC_COMMAND_COMPLETE,
+ MODE_READY, NULL);
+
+ if (event == -1)
+ return -1;
+
+ drv_ps1_event_enable(p->event = event);
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/free.c b/src/drv/ps1/cd/src/free.c
new file mode 100644
index 0000000..ed6f347
--- /dev/null
+++ b/src/drv/ps1/cd/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+
+void drv_ps1_cd_free(struct drv_ps1_cd *const cd)
+{
+}
diff --git a/src/drv/ps1/cd/src/getstat.c b/src/drv/ps1/cd/src/getstat.c
new file mode 100644
index 0000000..34bdaf5
--- /dev/null
+++ b/src/drv/ps1/cd/src/getstat.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/event.h>
+#include <kprintf.h>
+
+static int wait_event(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_getstat *const g = &p->u.getstat;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ p->available = !g->status.bits.shell_open;
+
+ if (!p->head)
+ return drv_ps1_cd_getstat();
+
+ return p->head->f();
+ }
+
+ return 0;
+}
+
+static int ensure_event(struct cd_prv *const p)
+{
+ if (p->event)
+ return 0;
+ else if ((p->event = drv_ps1_event_open(CLASS_CDROM, SPEC_COMMAND_COMPLETE,
+ MODE_READY, NULL)) == -1)
+ return -1;
+
+ drv_ps1_event_enable(p->event);
+ return 0;
+}
+
+int drv_ps1_cd_getstat(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_getstat *const g = &p->u.getstat;
+
+ /* TODO: CdAsyncGetStatus is *very* slow (~2.5 seconds / 10k calls) */
+ if (ensure_event(p))
+ return -1;
+ else if (!CdAsyncGetStatus(&g->status.byte))
+ {
+ kprintf("%s: CdAsyncGetStatus failed\n", __func__);
+ return -1;
+ }
+
+ p->next = wait_event;
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/init.c b/src/drv/ps1/cd/src/init.c
new file mode 100644
index 0000000..b452e82
--- /dev/null
+++ b/src/drv/ps1/cd/src/init.c
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_cd *drv_ps1_cd_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_cd *const ret = malloc(sizeof *ret);
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (!ret)
+ return NULL;
+ else if (!p->next && drv_ps1_cd_getstat())
+ goto failure;
+
+ *ret = (const struct drv_ps1_cd){.ev = *ev};
+ return ret;
+
+failure:
+ free(ret);
+ return NULL;
+}
diff --git a/src/drv/ps1/cd/src/next.c b/src/drv/ps1/cd/src/next.c
new file mode 100644
index 0000000..b26633a
--- /dev/null
+++ b/src/drv/ps1/cd/src/next.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <stdlib.h>
+
+int drv_ps1_cd_next(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_req *const next = p->head->next;
+
+ free(p->head);
+
+ if (next && next->f())
+ return -1;
+ else if (!(p->head = next))
+ return drv_ps1_cd_getstat();
+
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/prv.c b/src/drv/ps1/cd/src/prv.c
new file mode 100644
index 0000000..61ed4b4
--- /dev/null
+++ b/src/drv/ps1/cd/src/prv.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/types.h>
+
+struct cd_prv drv_ps1_cd_prv;
diff --git a/src/drv/ps1/cd/src/read.c b/src/drv/ps1/cd/src/read.c
new file mode 100644
index 0000000..d21cbae
--- /dev/null
+++ b/src/drv/ps1/cd/src/read.c
@@ -0,0 +1,239 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <drv/event.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int seek(void);
+
+static int deliver_event(struct cd_prv *const p, const int error)
+{
+ const struct cd_prv_read *const read = &p->u.read;
+ const struct cd_req *const req = p->head;
+ const struct drv_event_done *const d = &req->done;
+
+ drv_ps1_event_disable(read->endevent);
+ drv_ps1_event_close(read->endevent);
+ drv_ps1_event_disable(read->errevent);
+ drv_ps1_event_close(read->errevent);
+
+ if (!error)
+ {
+ const struct cd_req_read *const rr = &req->u.read;
+ const long offset = rr->offset % CD_SECTOR_SZ;
+
+ memcpy(rr->buf, p->sector + offset, rr->n);
+
+ if (!((p->offset += rr->n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+ }
+
+ if (d->f(error, d->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_read(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_prv_read *const read = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ p->sector_read = true;
+ return deliver_event(p, SUCCESS);
+ }
+ else if (drv_ps1_event_test(read->errevent)
+ || drv_ps1_event_test(read->endevent))
+ return deliver_event(p, EIO);
+
+ return 0;
+}
+
+static int uncached_read(struct cd_prv *const p)
+{
+ int endevent, errevent;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct CdAsyncReadSector_mode mode =
+ {
+ .mode.bits.speed = 1,
+ };
+
+ endevent = drv_ps1_event_open(CLASS_CDROM, SPEC_DATA_END, MODE_READY, NULL);
+ errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR, MODE_READY, NULL);
+
+ if (endevent == -1 || errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read)
+ {
+ .endevent = endevent,
+ .errevent = errevent
+ };
+
+ drv_ps1_event_enable(endevent);
+ drv_ps1_event_enable(errevent);
+
+ if (!CdAsyncReadSector(1, p->sector, mode))
+ goto failure;
+
+ p->next = wait_read;
+ return 0;
+
+failure:
+
+ if (endevent != -1)
+ {
+ drv_ps1_event_disable(endevent);
+ drv_ps1_event_close(endevent);
+ }
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int cached_read(struct cd_prv *const p)
+{
+ struct cd_req *const req = p->head;
+ struct cd_req_read *const rr = &req->u.read;
+ const struct drv_event_done *const done = &req->done;
+ const off_t offset = rr->offset % CD_SECTOR_SZ,
+ rem = CD_SECTOR_SZ - offset,
+ n = rr->n > rem ? rem : rr->n;
+
+ memcpy(rr->buf, p->sector + offset, n);
+
+ if (!((p->offset += n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+
+ if (done->f(SUCCESS, done->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const struct cd_prv_read *const r = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ drv_ps1_event_disable(r->errevent);
+ drv_ps1_event_close(r->errevent);
+ p->offset = rr->offset;
+ return uncached_read(p);
+ }
+ else if (drv_ps1_event_test(r->errevent))
+ return deliver_event(p, EIO);
+
+ return 0;
+}
+
+static int seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct cd_req_read *rr = &p->head->u.read;
+ const unsigned sector = rr->offset / CD_SECTOR_SZ;
+ const struct CdAsyncSeekL seekl = drv_ps1_cd_toseekl(sector);
+ const int errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR,
+ MODE_READY, NULL);
+
+ if (errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read){.errevent = errevent};
+ p->sector_read = false;
+ drv_ps1_event_enable(errevent);
+
+ if (!CdAsyncSeekL(&seekl))
+ goto failure;
+
+ p->next = wait_seek;
+ return 0;
+
+failure:
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int start(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const off_t cursect = p->offset / CD_SECTOR_SZ,
+ tgtsect = rr->offset / CD_SECTOR_SZ;
+
+ if (cursect != tgtsect || !p->sector_read)
+ return seek();
+
+ /* TODO: multi-sector reads, make sure cache can really be used */
+ return cached_read(p);
+}
+
+int drv_ps1_cd_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_req *const r = malloc(sizeof *r);
+
+ if (!r)
+ return -1;
+
+ *r = (const struct cd_req)
+ {
+ .f = start,
+ .done = *done,
+ .u.read =
+ {
+ .offset = offset,
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!p->head)
+ p->head = r;
+ else
+ p->tail->next = r;
+
+ p->tail = r;
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/readdebug b/src/drv/ps1/cd/src/readdebug
new file mode 100644
index 0000000..b2c09a7
--- /dev/null
+++ b/src/drv/ps1/cd/src/readdebug
@@ -0,0 +1,253 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <drv/event.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <drv/ps1/bios.h>
+
+static int seek(void);
+
+static int deliver_event(struct cd_prv *const p, const int error)
+{
+ const struct cd_prv_read *const read = &p->u.read;
+ const struct cd_req *const req = p->head;
+ const struct drv_event_done *const d = &req->done;
+
+ drv_ps1_event_disable(read->endevent);
+ drv_ps1_event_close(read->endevent);
+ drv_ps1_event_disable(read->errevent);
+ drv_ps1_event_close(read->errevent);
+
+ if (!error)
+ {
+ const struct cd_req_read *const rr = &req->u.read;
+ const long offset = rr->offset % CD_SECTOR_SZ;
+
+ memcpy(rr->buf, p->sector + offset, rr->n);
+
+ if (!((p->offset += rr->n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+ }
+
+ if (d->f(error, d->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_read(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_prv_read *const read = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ p->sector_read = true;
+ return deliver_event(p, SUCCESS);
+ }
+ else if (drv_ps1_event_test(read->errevent)
+ || drv_ps1_event_test(read->endevent))
+ return deliver_event(p, EIO);
+
+ return 0;
+}
+
+static int uncached_read(struct cd_prv *const p)
+{
+ int endevent, errevent;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct CdAsyncReadSector_mode mode =
+ {
+ .mode.bits.speed = 1,
+ };
+
+ endevent = drv_ps1_event_open(CLASS_CDROM, SPEC_DATA_END, MODE_READY, NULL);
+ errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR, MODE_READY, NULL);
+
+ if (endevent == -1 || errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read)
+ {
+ .endevent = endevent,
+ .errevent = errevent
+ };
+
+ drv_ps1_event_enable(endevent);
+ drv_ps1_event_enable(errevent);
+
+ Printf("preparing async read\n");
+ if (!CdAsyncReadSector(1, p->sector, mode))
+ goto failure;
+
+ p->next = wait_read;
+ return 0;
+
+failure:
+
+ if (endevent != -1)
+ {
+ drv_ps1_event_disable(endevent);
+ drv_ps1_event_close(endevent);
+ }
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int cached_read(struct cd_prv *const p)
+{
+ struct cd_req *const req = p->head;
+ struct cd_req_read *const rr = &req->u.read;
+ const struct drv_event_done *const done = &req->done;
+ const off_t offset = rr->offset % CD_SECTOR_SZ,
+ rem = CD_SECTOR_SZ - offset,
+ n = rr->n > rem ? rem : rr->n;
+
+ Printf("Doing %lu-byte cached read from offset %lu to %p\n",
+ (unsigned long) n, (unsigned long) offset, (void *)rr->buf);
+ memcpy(rr->buf, p->sector + offset, n);
+
+ if (!((p->offset += n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+
+ if (done->f(SUCCESS, done->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const struct cd_prv_read *const r = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ Printf("finished seeking\n");
+ drv_ps1_event_disable(r->errevent);
+ drv_ps1_event_close(r->errevent);
+ p->offset = rr->offset;
+ return uncached_read(p);
+ }
+ else if (drv_ps1_event_test(r->errevent))
+ {
+ Printf("failed to seek\n");
+ return deliver_event(p, EIO);
+ }
+
+ return 0;
+}
+
+static int seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct cd_req_read *rr = &p->head->u.read;
+ const unsigned sector = rr->offset / CD_SECTOR_SZ;
+ const struct CdAsyncSeekL seekl = drv_ps1_cd_toseekl(sector);
+ const int errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR,
+ MODE_READY, NULL);
+
+ if (errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read){.errevent = errevent};
+ p->sector_read = false;
+ drv_ps1_event_enable(errevent);
+
+ Printf("Seeking to offset %lu\n", (unsigned long)rr->offset);
+
+ if (!CdAsyncSeekL(&seekl))
+ goto failure;
+
+ p->next = wait_seek;
+ return 0;
+
+failure:
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int start(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const off_t cursect = p->offset / CD_SECTOR_SZ,
+ tgtsect = rr->offset / CD_SECTOR_SZ;
+
+ if (cursect != tgtsect || !p->sector_read)
+ return seek();
+
+ /* TODO: multi-sector reads, make sure cache can really be used */
+ return cached_read(p);
+}
+
+int drv_ps1_cd_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_req *const r = malloc(sizeof *r);
+
+ if (!r)
+ return -1;
+
+ *r = (const struct cd_req)
+ {
+ .f = start,
+ .done = *done,
+ .u.read =
+ {
+ .offset = offset,
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!p->head)
+ p->head = r;
+ else
+ p->tail->next = r;
+
+ p->tail = r;
+ Printf("Added %p {.buf=%p, .n=%lu} to read reqs\n", (void *)p->tail, buf,
+ (unsigned long)n);
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/send.c b/src/drv/ps1/cd/src/send.c
new file mode 100644
index 0000000..01aa5cb
--- /dev/null
+++ b/src/drv/ps1/cd/src/send.c
@@ -0,0 +1,101 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cd/regs.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <stdint.h>
+
+static int wait_event(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ const union cd_prv_getstat g = {.status = CD_REG_RSP->rsp};
+
+ p->available = !g.bits.shell_open;
+ }
+
+ return 0;
+}
+
+static void send_params(const struct cd_prv *const p)
+{
+ static const size_t n[] =
+ {
+ [CMD_SETLOC] = sizeof (struct cmd_setloc)
+ };
+
+ const uint8_t cmd = p->cmd.cmd, index = CD_REG_STATUS->index;
+
+ if (cmd < sizeof n / sizeof *n)
+ {
+ const void *const vbuf = &p->cmd.params;
+ const uint8_t *buf = vbuf;
+
+ CD_REG_STATUS->index = 0;
+
+ for (size_t i = 0; i < n[cmd]; i++)
+ CD_REG_PARAM->param = *buf++;
+
+ CD_REG_STATUS->index = index;
+ }
+}
+
+static int send_data(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (CD_REG_STATUS->BUSYSTS)
+ return 0;
+
+ send_params(p);
+ CD_REG_CMD->cmd = p->cmd.cmd;
+ p->next = wait_event;
+ return 0;
+}
+
+static int reset_param_fifo(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (CD_REG_STATUS->BUSYSTS)
+ return 0;
+
+ CD_REG_IF->w.ack = 0x1f;
+ CD_REG_STATUS->index = 1;
+ CD_REG_IF->w.CLRPRM = 1;
+ p->next = send_data;
+ return 0;
+}
+
+int drv_ps1_cd_send(const struct cmd *const cmd)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (drv_ps1_cd_ensure_event(p))
+ return -1;
+
+ p->cmd = *cmd;
+ p->next = reset_param_fifo;
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/toseekl.c b/src/drv/ps1/cd/src/toseekl.c
new file mode 100644
index 0000000..ee776c9
--- /dev/null
+++ b/src/drv/ps1/cd/src/toseekl.c
@@ -0,0 +1,54 @@
+/* Original functions from psn00bsdk, commit 5d9aa2d3
+ *
+ * itob extracted from libpsn00b/include/psxcd.h
+ * CdIntToPos (here renamed to drv_ps1_cd_toseekl) extracted from
+ * libpsn00b/psxcd/misc.c
+ *
+ * Original copyright notice:
+ *
+ * PSn00bSDK CD-ROM library
+ * (C) 2020-2023 Lameguy64, spicyjpeg - MPL licensed
+ */
+
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/bios.h>
+
+/**
+ * @brief Translates a decimal value to BCD.
+ *
+ * @details Translates a decimal integer in 0-99 range into a BCD format value.
+ */
+static unsigned itob(const unsigned i)
+{
+ return ((i / 10) * 16) | (i % 10);
+}
+
+struct CdAsyncSeekL drv_ps1_cd_toseekl(unsigned i)
+{
+ i += 150;
+
+ return (const struct CdAsyncSeekL)
+ {
+ .minutes = itob(i / (75 * 60)),
+ .seconds = itob((i / 75) % 60),
+ .frames = itob(i % 75)
+ };
+}
diff --git a/src/drv/ps1/cd/src/update.c b/src/drv/ps1/cd/src/update.c
new file mode 100644
index 0000000..148dd87
--- /dev/null
+++ b/src/drv/ps1/cd/src/update.c
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/event.h>
+#include <stdbool.h>
+
+int drv_ps1_cd_update(struct drv_ps1_cd *const cd)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (p->next())
+ return -1;
+ else if (p->available ^ cd->available)
+ {
+ const struct drv_event *const ev = &cd->ev;
+ static const struct drv_event_ops ops =
+ {
+ .read = drv_ps1_cd_read,
+ .write = drv_ps1_cd_write
+ };
+
+ if (ev->status("cd0", &ops, p->available, 0440, ev->args))
+ return -1;
+
+ cd->available = p->available;
+ }
+
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/virt/CMakeLists.txt b/src/drv/ps1/cd/src/virt/CMakeLists.txt
new file mode 100644
index 0000000..0e5bd1b
--- /dev/null
+++ b/src/drv/ps1/cd/src/virt/CMakeLists.txt
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_cd PRIVATE
+ # free.c
+ init.c
+ # next.c
+ # prv.c
+ # read.c
+ # update.c
+ # write.c
+)
diff --git a/src/drv/ps1/cd/src/virt/init.c b/src/drv/ps1/cd/src/virt/init.c
new file mode 100644
index 0000000..204f7fa
--- /dev/null
+++ b/src/drv/ps1/cd/src/virt/init.c
@@ -0,0 +1,41 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/virt/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_cd *drv_ps1_cd_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_cd *const ret = malloc(sizeof *ret);
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (!ret)
+ return NULL;
+ else if (!p->next && drv_ps1_cd_getstat())
+ goto failure;
+
+ *ret = (const struct drv_ps1_cd){.ev = *ev};
+ return ret;
+
+failure:
+ free(ret);
+ return NULL;
+}
diff --git a/src/drv/ps1/cd/src/write.c b/src/drv/ps1/cd/src/write.c
new file mode 100644
index 0000000..ba47993
--- /dev/null
+++ b/src/drv/ps1/cd/src/write.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/event.h>
+#include <errno.h>
+
+int drv_ps1_cd_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const done, void *const args)
+{
+ /* TODO: write event callback returning EROFS */
+ errno = EROFS;
+ return -1;
+}
diff --git a/src/drv/ps1/cpu/CMakeLists.txt b/src/drv/ps1/cpu/CMakeLists.txt
new file mode 100644
index 0000000..dafb0cd
--- /dev/null
+++ b/src/drv/ps1/cpu/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_cpu INTERFACE)
+target_include_directories(drv_ps1_cpu INTERFACE include)
diff --git a/src/drv/ps1/cpu/include/drv/ps1/cpu.h b/src/drv/ps1/cpu/include/drv/ps1/cpu.h
new file mode 100644
index 0000000..d951f48
--- /dev/null
+++ b/src/drv/ps1/cpu/include/drv/ps1/cpu.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CPU_H
+#define DRV_PS1_CPU_H
+
+#define DRV_PS1_CPU_F 33868800ul
+
+#endif
diff --git a/src/drv/ps1/dma/CMakeLists.txt b/src/drv/ps1/dma/CMakeLists.txt
new file mode 100644
index 0000000..0daeee9
--- /dev/null
+++ b/src/drv/ps1/dma/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_dma INTERFACE)
+target_include_directories(drv_ps1_dma INTERFACE include)
diff --git a/src/drv/ps1/dma/include/drv/ps1/dma.h b/src/drv/ps1/dma/include/drv/ps1/dma.h
new file mode 100644
index 0000000..9538c3b
--- /dev/null
+++ b/src/drv/ps1/dma/include/drv/ps1/dma.h
@@ -0,0 +1,97 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_DMA_H
+#define DRV_PS1_DMA_H
+
+#include <stdint.h>
+
+union dpcr
+{
+ struct
+ {
+ uint32_t mdecin_prio :3, mdecin_en :1, mdecout_prio :3, mdecout_en :1,
+ gpu_prio :3, gpu_en :1, cdrom_prio :3, cdrom_en :1, spu_prio :3,
+ spu_en :1, pio_prio :3, pio_en :1, otc_prio :3, otc_en :1, :4;
+ } bits;
+
+ uint32_t mask;
+};
+
+union madr
+{
+ struct
+ {
+ uint32_t addr :24, :8;
+ } bits;
+
+ uint32_t mask;
+};
+
+union bcr
+{
+ struct
+ {
+ uint16_t nwords, reserved;
+ } syncmode_0;
+
+ struct
+ {
+ uint16_t blocksz, nblocks;
+ } syncmode_1;
+
+ struct
+ {
+ uint32_t reserved;
+ } syncmode_2;
+
+ uint32_t mask;
+};
+
+enum
+{
+ CHCR_DIR_TO_RAM,
+ CHCR_DIR_FROM_RAM
+};
+
+enum
+{
+ CHCR_SYNC_MODE_ALL,
+ CHCR_SYNC_MODE_BLOCKS,
+ CHCR_SYNC_MODE_LINKED_LIST
+};
+
+union chcr
+{
+ struct
+ {
+ uint32_t dir :1, memstep :1, :6, chopping :1, sync_mode :2, :5,
+ chopping_dma_window_sz :3, :1, chopping_cpu_window_sz :3, :1,
+ start_busy :1, :3, start_trigger :1, :3;
+ } bits;
+
+ uint32_t mask;
+};
+
+#define DMA_BASE(dma, off) ((dma) * 0x10 + 0x1f801080 + (off))
+#define D2_MADR ((volatile union madr *)DMA_BASE(2, 0))
+#define D2_BCR ((volatile union bcr *)DMA_BASE(2, 4))
+#define D2_CHCR ((volatile union chcr *)DMA_BASE(2, 8))
+#define DPCR ((volatile union dpcr *)0x1f8010f0)
+
+#endif
diff --git a/src/drv/ps1/event/CMakeLists.txt b/src/drv/ps1/event/CMakeLists.txt
new file mode 100644
index 0000000..2b00aaa
--- /dev/null
+++ b/src/drv/ps1/event/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_event)
+add_subdirectory(src)
+target_include_directories(drv_ps1_event PUBLIC include)
+target_link_libraries(drv_ps1_event PUBLIC c drv_ps1_bios)
diff --git a/src/drv/ps1/event/include/drv/ps1/event.h b/src/drv/ps1/event/include/drv/ps1/event.h
new file mode 100644
index 0000000..2c34b02
--- /dev/null
+++ b/src/drv/ps1/event/include/drv/ps1/event.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_EVENT_H
+#define DRV_PS1_EVENT_H
+
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_open(int class, int spec, int mode, int (*f)(void));
+int drv_ps1_event_test(int event);
+int drv_ps1_event_wait(int event);
+int drv_ps1_event_enable(int event);
+int drv_ps1_event_disable(int event);
+int drv_ps1_event_close(int event);
+
+#endif
diff --git a/src/drv/ps1/event/src/CMakeLists.txt b/src/drv/ps1/event/src/CMakeLists.txt
new file mode 100644
index 0000000..e741edc
--- /dev/null
+++ b/src/drv/ps1/event/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_event PRIVATE
+ close.c
+ disable.c
+ enable.c
+ open.c
+ test.c
+)
diff --git a/src/drv/ps1/event/src/close.c b/src/drv/ps1/event/src/close.c
new file mode 100644
index 0000000..01c9a33
--- /dev/null
+++ b/src/drv/ps1/event/src/close.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_close(const int event)
+{
+ return CloseEvent(event);
+}
diff --git a/src/drv/ps1/event/src/disable.c b/src/drv/ps1/event/src/disable.c
new file mode 100644
index 0000000..6d32b2b
--- /dev/null
+++ b/src/drv/ps1/event/src/disable.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_disable(const int event)
+{
+ return DisableEvent(event);
+}
diff --git a/src/drv/ps1/event/src/enable.c b/src/drv/ps1/event/src/enable.c
new file mode 100644
index 0000000..3368ac4
--- /dev/null
+++ b/src/drv/ps1/event/src/enable.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_enable(const int event)
+{
+ return EnableEvent(event);
+}
diff --git a/src/drv/ps1/event/src/open.c b/src/drv/ps1/event/src/open.c
new file mode 100644
index 0000000..6bb55f1
--- /dev/null
+++ b/src/drv/ps1/event/src/open.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_open(const int class, const int spec, const int mode,
+ int (*const f)(void))
+{
+ int ret;
+
+ EnterCriticalSection();
+ ret = OpenEvent(class, spec, mode, f);
+ ExitCriticalSection();
+ return ret;
+}
diff --git a/src/drv/ps1/event/src/test.c b/src/drv/ps1/event/src/test.c
new file mode 100644
index 0000000..358bd8e
--- /dev/null
+++ b/src/drv/ps1/event/src/test.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_test(const int event)
+{
+ int ret;
+
+ ret = TestEvent(event);
+ return ret;
+}
diff --git a/src/drv/ps1/gpu/CMakeLists.txt b/src/drv/ps1/gpu/CMakeLists.txt
new file mode 100644
index 0000000..a86ab92
--- /dev/null
+++ b/src/drv/ps1/gpu/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_gpu INTERFACE)
+target_include_directories(drv_ps1_gpu INTERFACE include)
diff --git a/src/drv/ps1/gpu/include/drv/ps1/gpu.h b/src/drv/ps1/gpu/include/drv/ps1/gpu.h
new file mode 100644
index 0000000..1afc5f6
--- /dev/null
+++ b/src/drv/ps1/gpu/include/drv/ps1/gpu.h
@@ -0,0 +1,173 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_GPU_H
+#define DRV_PS1_GPU_H
+
+#include <stdint.h>
+
+enum
+{
+ GP0_FILL_VRAM = 0x02,
+ GP0_TEXTRECT_VARSZ_OPAQ_RAW = 0x65,
+ GP0_COPY_RECT_CPU_VRAM = 0xa0,
+ GP0_COPY_RECT_VRAM_CPU = 0xc0,
+ GP0_DRAW_MODE = 0xe1,
+ GP0_TEX_WINDOW,
+ GP0_DRAW_AREA_TOP_LEFT,
+ GP0_DRAW_AREA_BOTTOM_RIGHT,
+ GP0_DRAW_OFFSET,
+ GP0_DRAW_MASK_BIT
+};
+
+enum
+{
+ GP1_RESET_GPU,
+ GP1_RESET_CMDBUF,
+ GP1_ACK_IRQ,
+ GP1_DISPLAY_ENABLE,
+ GP1_DMA_DIR,
+ GP1_START_DISPLAY_AREA,
+ GP1_H_DISPLAY_RANGE,
+ GP1_V_DISPLAY_RANGE,
+ GP1_DISPLAY_MODE
+};
+
+enum
+{
+ GP1_DMA_DIR_OFF,
+ GP1_DMA_DIR_FIFO,
+ GP1_DMA_DIR_CPU_TO_GP0,
+ GP1_DMA_DIR_GPUREAD_TO_CPU
+};
+
+union drv_ps1_gpu_gp0
+{
+ uint32_t mask;
+
+ struct
+ {
+ uint32_t w :16, h :16, x :16, y :16, r :8, g :8, b :8, cmd :8;
+ } fill_vram;
+
+ struct
+ {
+ uint32_t :24, cmd :8;
+ } copy_rect;
+
+ struct
+ {
+ uint16_t x, y;
+ } coord;
+
+ struct
+ {
+ uint16_t w, h;
+ } size;
+
+ struct
+ {
+ uint32_t page_x :4, page_y :1, stp :2, bpp :2, dither :1,
+ draw_to_display :1, tex_disable :1, xflip :1, yflip :1, :10,
+ cmd :8;
+ } draw_mode;
+
+ struct
+ {
+ uint32_t mask_x :5, mask_y :5, off_x :5, off_y :5, :4, cmd :8;
+ } tex_window;
+
+ struct
+ {
+ uint32_t x :10, y :9, :5, cmd :8;
+ } draw_area_tl, draw_area_br;
+
+ struct
+ {
+ int32_t x :11, y :11, :2, cmd :8;
+ } offset;
+
+ struct
+ {
+ uint32_t set :1, check :1, :22, cmd :8;
+ } mask_bit;
+};
+
+union drv_ps1_gpu_gp1
+{
+ uint32_t mask;
+
+ struct
+ {
+ uint32_t :24, cmd:8;
+ } reset_gpu, reset_cmdbuf, ack_irq;
+
+ struct
+ {
+ uint32_t disable :1, :23, cmd :8;
+ } display;
+
+ struct
+ {
+ uint32_t dir :2, :22, cmd :8;
+ } dma;
+
+ struct
+ {
+ uint32_t x :10, y :9, :5, cmd :8;
+ } disparea;
+
+ struct
+ {
+ uint32_t x1 :12, x2 :12, cmd :8;
+ } h_display_range;
+
+ struct
+ {
+ uint32_t y1 :10, y2 :10, :4, cmd :8;
+ } v_display_range;
+
+ struct
+ {
+ uint32_t hres :2, vres :1, vmode :1, coldepth :1, vinterlace :1,
+ hres2 :1, reverse :1, :16, cmd :8;
+ } display_mode;
+};
+
+union drv_ps1_gpu_stat
+{
+ struct
+ {
+ uint32_t x_base :4, y_base :1, stp :2, bpp :2, dither :1,
+ draw_to_display :1, set_mask :1, draw_pix :1, interlace :1,
+ reverse :1, disable :1, xres2 :1, xres1 :2, yres :1, vmode :1,
+ coldepth :1, vinterlace :1, display_enable :1, irq_req :1,
+ dma_req :1, ready_cmd :1, ready_send :1, ready_dma :1, dma_dir :2,
+ draw_odd :1;
+ } bits;
+
+ uint32_t mask;
+};
+
+#define GPU_BASE 0x1f801810
+#define GPU_REG(x) (GPU_BASE + (x))
+#define GP0 ((volatile union drv_ps1_gpu_gp0 *)GPU_REG(0))
+#define GP1 ((volatile union drv_ps1_gpu_gp1 *)GPU_REG(4))
+#define GPUSTAT ((volatile const union drv_ps1_gpu_stat *)GPU_REG(4))
+
+#endif
diff --git a/src/drv/ps1/include/drv/ps1.h b/src/drv/ps1/include/drv/ps1.h
new file mode 100644
index 0000000..7d92878
--- /dev/null
+++ b/src/drv/ps1/include/drv/ps1.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_H
+#define DRV_PS1_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_ps1_init(const struct drv_event *ev);
+int drv_ps1_update(struct drv_port *p);
+void drv_ps1_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/ps1/irq/CMakeLists.txt b/src/drv/ps1/irq/CMakeLists.txt
new file mode 100644
index 0000000..8327cd5
--- /dev/null
+++ b/src/drv/ps1/irq/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_irq)
+add_subdirectory(src)
+target_include_directories(drv_ps1_irq PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_irq PUBLIC c PRIVATE drv_ps1_bios)
diff --git a/src/drv/ps1/irq/include/drv/ps1/irq.h b/src/drv/ps1/irq/include/drv/ps1/irq.h
new file mode 100644
index 0000000..0d40c7f
--- /dev/null
+++ b/src/drv/ps1/irq/include/drv/ps1/irq.h
@@ -0,0 +1,64 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_IRQ_H
+#define DRV_PS1_IRQ_H
+
+#include <stdint.h>
+
+union drv_ps1_statmask
+{
+ struct
+ {
+ uint32_t vblank :1, gpu :1, cdrom :1, dma :1, tmr0 :1, tmr1 :1, tmr2 :1,
+ controller :1, sio :1, spu :1, lightpen :1, :21;
+ } bits;
+
+ uint32_t mask;
+};
+
+#define I_BASE(x) (0x1f801070 + (x))
+#define I_STAT ((volatile union drv_ps1_statmask *)I_BASE(0))
+#define I_MASK ((volatile union drv_ps1_statmask *)I_BASE(4))
+
+enum drv_ps1_irq
+{
+ IRQ_VBLANK,
+ IRQ_GPU,
+ IRQ_CDROM,
+ IRQ_DMA,
+ IRQ_TMR0,
+ IRQ_TMR1,
+ IRQ_TMR2,
+ IRQ_JOYPAD_MEMCARD,
+ IRQ_SIO,
+ IRQ_SPU,
+ IRQ_JOYPAD_IO
+};
+
+struct drv_ps1_irq_src
+{
+ int mask;
+ int (*fn)(void);
+ struct drv_ps1_irq_src *next;
+};
+
+int drv_ps1_irq_init(void);
+int drv_ps1_irq_set(struct drv_ps1_irq_src *src);
+
+#endif
diff --git a/src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h b/src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h
new file mode 100644
index 0000000..39b7448
--- /dev/null
+++ b/src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_IRQ_ROUTINES_H
+#define DRV_PS1_IRQ_ROUTINES_H
+
+void drv_ps1_irq_handler(void);
+
+#endif
diff --git a/src/drv/ps1/irq/private_include/drv/ps1/irq/types.h b/src/drv/ps1/irq/private_include/drv/ps1/irq/types.h
new file mode 100644
index 0000000..6c5a185
--- /dev/null
+++ b/src/drv/ps1/irq/private_include/drv/ps1/irq/types.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_IRQ_TYPES_H
+#define DRV_PS1_IRQ_TYPES_H
+
+#include <drv/ps1/irq.h>
+
+extern struct drv_ps1_irq_src *drv_ps1_irq_head;
+
+#endif
diff --git a/src/drv/ps1/irq/src/CMakeLists.txt b/src/drv/ps1/irq/src/CMakeLists.txt
new file mode 100644
index 0000000..3823f4e
--- /dev/null
+++ b/src/drv/ps1/irq/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_irq PRIVATE
+ handler.c
+ head.c
+ init.c
+ set.c
+)
diff --git a/src/drv/ps1/irq/src/handler.c b/src/drv/ps1/irq/src/handler.c
new file mode 100644
index 0000000..0861852
--- /dev/null
+++ b/src/drv/ps1/irq/src/handler.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/routines.h>
+#include <drv/ps1/irq/types.h>
+#include <drv/ps1/bios.h>
+#include <stddef.h>
+
+void drv_ps1_irq_handler(void)
+{
+ for (struct drv_ps1_irq_src *s = drv_ps1_irq_head; s; s = s->next)
+ if (I_STAT->mask & s->mask)
+ s->fn();
+
+ ReturnFromException();
+}
diff --git a/src/drv/ps1/irq/src/head.c b/src/drv/ps1/irq/src/head.c
new file mode 100644
index 0000000..cde1fd8
--- /dev/null
+++ b/src/drv/ps1/irq/src/head.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/types.h>
+
+struct drv_ps1_irq_src *drv_ps1_irq_head;
diff --git a/src/drv/ps1/irq/src/init.c b/src/drv/ps1/irq/src/init.c
new file mode 100644
index 0000000..9e92b01
--- /dev/null
+++ b/src/drv/ps1/irq/src/init.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/routines.h>
+#include <drv/ps1/bios.h>
+#include <setjmp.h>
+
+int drv_ps1_irq_init(void)
+{
+ static jmp_buf jmp;
+ static char stack[128];
+ const int critical = EnterCriticalSection();
+
+ if (SaveState(jmp))
+ drv_ps1_irq_handler();
+
+ jmp->sp = (unsigned)stack + sizeof stack - 4;
+ SetCustomExitFromException(jmp);
+
+ if (critical)
+ ExitCriticalSection();
+
+ return 0;
+}
diff --git a/src/drv/ps1/irq/src/set.c b/src/drv/ps1/irq/src/set.c
new file mode 100644
index 0000000..35c5ed0
--- /dev/null
+++ b/src/drv/ps1/irq/src/set.c
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/types.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_irq_set(struct drv_ps1_irq_src *const src)
+{
+ if (!drv_ps1_irq_head)
+ drv_ps1_irq_head = src;
+ else
+ for (struct drv_ps1_irq_src *s = drv_ps1_irq_head; s; s = s->next)
+ if (!s->next)
+ {
+ s->next = src;
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/drv/ps1/mc/CMakeLists.txt b/src/drv/ps1/mc/CMakeLists.txt
new file mode 100644
index 0000000..ef232ef
--- /dev/null
+++ b/src/drv/ps1/mc/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_mc)
+add_subdirectory(src)
+target_include_directories(drv_ps1_mc PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_mc PUBLIC c drv_event)
diff --git a/src/drv/ps1/mc/include/drv/ps1/mc.h b/src/drv/ps1/mc/include/drv/ps1/mc.h
new file mode 100644
index 0000000..2e90776
--- /dev/null
+++ b/src/drv/ps1/mc/include/drv/ps1/mc.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_MC_H
+#define DRV_PS1_MC_H
+
+#include <drv/event.h>
+
+struct drv_ps1_mc *drv_ps1_mc_init(const struct drv_event *ev);
+int drv_ps1_mc_update(struct drv_ps1_mc *mc);
+void drv_ps1_mc_free(struct drv_ps1_mc *mc);
+
+#endif
diff --git a/src/drv/ps1/mc/private_include/drv/ps1/mc/types.h b/src/drv/ps1/mc/private_include/drv/ps1/mc/types.h
new file mode 100644
index 0000000..14606e5
--- /dev/null
+++ b/src/drv/ps1/mc/private_include/drv/ps1/mc/types.h
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_MC_TYPES_H
+#define DRV_PS1_MC_TYPES_H
+
+#include <drv/event.h>
+
+struct drv_ps1_mc
+{
+ const struct drv_event *ev;
+};
+
+enum
+{
+ MC_0,
+ MC_1,
+
+ N_MC
+};
+
+#endif
diff --git a/src/drv/ps1/mc/src/CMakeLists.txt b/src/drv/ps1/mc/src/CMakeLists.txt
new file mode 100644
index 0000000..ae1378c
--- /dev/null
+++ b/src/drv/ps1/mc/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_mc PRIVATE
+ free.c
+ init.c
+ update.c
+)
diff --git a/src/drv/ps1/mc/src/free.c b/src/drv/ps1/mc/src/free.c
new file mode 100644
index 0000000..bdf54ff
--- /dev/null
+++ b/src/drv/ps1/mc/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/mc.h>
+
+void drv_ps1_mc_free(struct drv_ps1_mc *const mc)
+{
+}
diff --git a/src/drv/ps1/mc/src/init.c b/src/drv/ps1/mc/src/init.c
new file mode 100644
index 0000000..88be46a
--- /dev/null
+++ b/src/drv/ps1/mc/src/init.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/mc.h>
+#include <drv/ps1/mc/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_mc *drv_ps1_mc_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_mc *const ret = malloc(sizeof *ret);
+
+ if (!ret)
+ return NULL;
+
+ *ret = (const struct drv_ps1_mc){.ev = ev};
+ return ret;
+}
diff --git a/src/drv/ps1/mc/src/update.c b/src/drv/ps1/mc/src/update.c
new file mode 100644
index 0000000..866bf94
--- /dev/null
+++ b/src/drv/ps1/mc/src/update.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/mc.h>
+#include <drv/event.h>
+
+int drv_ps1_mc_update(struct drv_ps1_mc *const mc)
+{
+ /* TODO */
+ return 0;
+}
diff --git a/src/drv/ps1/pad/CMakeLists.txt b/src/drv/ps1/pad/CMakeLists.txt
new file mode 100644
index 0000000..eb74091
--- /dev/null
+++ b/src/drv/ps1/pad/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_pad)
+add_subdirectory(src)
+target_include_directories(drv_ps1_pad PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_pad PUBLIC c drv_event)
diff --git a/src/drv/ps1/pad/include/drv/ps1/pad.h b/src/drv/ps1/pad/include/drv/ps1/pad.h
new file mode 100644
index 0000000..9cc2fc6
--- /dev/null
+++ b/src/drv/ps1/pad/include/drv/ps1/pad.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_PAD_H
+#define DRV_PS1_PAD_H
+
+#include <drv/event.h>
+
+struct drv_ps1_pad *drv_ps1_pad_init(const struct drv_event *ev);
+int drv_ps1_pad_update(struct drv_ps1_pad *pad);
+void drv_ps1_pad_free(struct drv_ps1_pad *pad);
+
+#endif
diff --git a/src/drv/ps1/pad/private_include/drv/ps1/pad/types.h b/src/drv/ps1/pad/private_include/drv/ps1/pad/types.h
new file mode 100644
index 0000000..c164a30
--- /dev/null
+++ b/src/drv/ps1/pad/private_include/drv/ps1/pad/types.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_PAD_TYPES_H
+#define DRV_PS1_PAD_TYPES_H
+
+#include <drv/event.h>
+
+struct drv_ps1_pad
+{
+ const struct drv_event *ev;
+};
+
+#endif
diff --git a/src/drv/ps1/pad/src/CMakeLists.txt b/src/drv/ps1/pad/src/CMakeLists.txt
new file mode 100644
index 0000000..bfae1a1
--- /dev/null
+++ b/src/drv/ps1/pad/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_pad PRIVATE
+ free.c
+ init.c
+ update.c
+)
diff --git a/src/drv/ps1/pad/src/free.c b/src/drv/ps1/pad/src/free.c
new file mode 100644
index 0000000..1498f2d
--- /dev/null
+++ b/src/drv/ps1/pad/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/pad.h>
+
+void drv_ps1_pad_free(struct drv_ps1_pad *const pad)
+{
+}
diff --git a/src/drv/ps1/pad/src/init.c b/src/drv/ps1/pad/src/init.c
new file mode 100644
index 0000000..8fe3ccb
--- /dev/null
+++ b/src/drv/ps1/pad/src/init.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/pad.h>
+#include <drv/ps1/pad/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_pad *drv_ps1_pad_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_pad *const ret = malloc(sizeof *ret);
+
+ if (!ret)
+ return NULL;
+
+ *ret = (const struct drv_ps1_pad){.ev = ev};
+ return ret;
+}
diff --git a/src/drv/ps1/pad/src/update.c b/src/drv/ps1/pad/src/update.c
new file mode 100644
index 0000000..9c9acfe
--- /dev/null
+++ b/src/drv/ps1/pad/src/update.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/pad.h>
+#include <drv/event.h>
+
+int drv_ps1_pad_update(struct drv_ps1_pad *const pad)
+{
+ /* TODO */
+ return 0;
+}
diff --git a/src/drv/ps1/private_include/drv/ps1/types.h b/src/drv/ps1/private_include/drv/ps1/types.h
new file mode 100644
index 0000000..35cb14e
--- /dev/null
+++ b/src/drv/ps1/private_include/drv/ps1/types.h
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_TYPES_H
+#define DRV_PS1_TYPES_H
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+
+struct drv_port
+{
+ struct drv_ps1_mc *mc;
+ struct drv_ps1_cd *cd;
+ struct drv_ps1_pad *pad;
+ struct drv_ps1_sio *sio;
+};
+
+#endif
diff --git a/src/drv/ps1/rcnt/CMakeLists.txt b/src/drv/ps1/rcnt/CMakeLists.txt
new file mode 100644
index 0000000..f5b5171
--- /dev/null
+++ b/src/drv/ps1/rcnt/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_rcnt)
+add_subdirectory(src)
+target_include_directories(drv_ps1_rcnt PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_rcnt
+ PUBLIC c
+ PRIVATE drv_ps1_bios drv_ps1_irq drv_ps1_event)
diff --git a/src/drv/ps1/rcnt/include/drv/ps1/rcnt.h b/src/drv/ps1/rcnt/include/drv/ps1/rcnt.h
new file mode 100644
index 0000000..831012c
--- /dev/null
+++ b/src/drv/ps1/rcnt/include/drv/ps1/rcnt.h
@@ -0,0 +1,45 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_RCNT_H
+#define DRV_PS1_RCNT_H
+
+#include <stdint.h>
+
+union drv_ps1_rcnt_cfg
+{
+ struct
+ {
+ uint32_t sync_enable :1, sync_mode :2, reset :1, irq_tgt :1,
+ irq_max :1, repeat :1, pulse_toggle :1, clocksrc :2, intreq :1;
+ } bits;
+
+ uint32_t word;
+};
+
+enum drv_ps1_rcnt
+{
+ DRV_PS1_RCNT0,
+ DRV_PS1_RCNT1,
+ DRV_PS1_RCNT2
+};
+
+int drv_ps1_rcnt_init(enum drv_ps1_rcnt rcnt, uint16_t target,
+ const union drv_ps1_rcnt_cfg *cfg, int (*f)(void));
+
+#endif
diff --git a/src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h b/src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h
new file mode 100644
index 0000000..a6c9750
--- /dev/null
+++ b/src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_RCNT_REGS_H
+#define DRV_PS1_RCNT_REGS_H
+
+#include <drv/ps1/rcnt.h>
+#include <stdint.h>
+
+struct rcnt_value
+{
+ uint32_t value :16, :16;
+};
+
+#define RCNT_BASE(n) (0x1f801100 + (n << 4))
+#define RCNT_REG(n, m) (RCNT_BASE(n) + m)
+#define RCNT_VALUE(n) ((volatile struct rcnt_value *)RCNT_REG(n, 0))
+#define RCNT_MODE(n) ((volatile union drv_ps1_rcnt_cfg *)RCNT_REG(n, 4))
+#define RCNT_TARGET(n) ((volatile struct rcnt_value *)RCNT_REG(n, 8))
+
+#endif
diff --git a/src/drv/ps1/rcnt/src/CMakeLists.txt b/src/drv/ps1/rcnt/src/CMakeLists.txt
new file mode 100644
index 0000000..4e8eb88
--- /dev/null
+++ b/src/drv/ps1/rcnt/src/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_rcnt PRIVATE
+ init.c
+)
diff --git a/src/drv/ps1/rcnt/src/init.c b/src/drv/ps1/rcnt/src/init.c
new file mode 100644
index 0000000..0c4327c
--- /dev/null
+++ b/src/drv/ps1/rcnt/src/init.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/rcnt.h>
+#include <drv/ps1/rcnt/regs.h>
+#include <drv/ps1/event.h>
+#include <drv/ps1/irq.h>
+#include <drv/ps1/bios.h>
+#include <stddef.h>
+#include <stdint.h>
+
+int drv_ps1_rcnt_init(const enum drv_ps1_rcnt rcnt, const uint16_t target,
+ const union drv_ps1_rcnt_cfg *const cfg, int (*const f)(void))
+{
+ int class;
+
+ EnterCriticalSection();
+ RCNT_TARGET(rcnt)->value = target;
+ *RCNT_MODE(rcnt) = *cfg;
+
+ switch (rcnt)
+ {
+ case DRV_PS1_RCNT0:
+ I_MASK->bits.tmr0 = 1;
+ class = CLASS_RTC0;
+ break;
+ case DRV_PS1_RCNT1:
+ I_MASK->bits.tmr1 = 1;
+ class = CLASS_RTC1;
+ break;
+ case DRV_PS1_RCNT2:
+ I_MASK->bits.tmr2 = 1;
+ class = CLASS_RTC2;
+ break;
+ }
+
+ ExitCriticalSection();
+
+ const int event = drv_ps1_event_open(class, SPEC_INTERRUPTED,
+ MODE_EXECUTE, f);
+
+ if (event == -1)
+ return -1;
+
+ drv_ps1_event_enable(event);
+ return 0;
+}
diff --git a/src/drv/ps1/sio/CMakeLists.txt b/src/drv/ps1/sio/CMakeLists.txt
new file mode 100644
index 0000000..f382e08
--- /dev/null
+++ b/src/drv/ps1/sio/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_sio)
+add_subdirectory(src)
+target_include_directories(drv_ps1_sio PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_sio
+ PUBLIC c
+ PRIVATE drv drv_ps1_bios drv_ps1_cpu drv_ps1_irq)
diff --git a/src/drv/ps1/sio/include/drv/ps1/sio.h b/src/drv/ps1/sio/include/drv/ps1/sio.h
new file mode 100644
index 0000000..3fabadd
--- /dev/null
+++ b/src/drv/ps1/sio/include/drv/ps1/sio.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_H
+#define DRV_PS1_SIO_H
+
+#include <drv/event.h>
+
+struct drv_ps1_sio *drv_ps1_sio_init(const struct drv_event *ev);
+int drv_ps1_sio_update(struct drv_ps1_sio *sio);
+void drv_ps1_sio_free(struct drv_ps1_sio *sio);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
new file mode 100644
index 0000000..a481fa9
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_OPS_H
+#define DRV_PS1_SIO_OPS_H
+
+#include <drv/event.h>
+#include <sys/types.h>
+
+int drv_ps1_sio_read(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_sio_read_nb(void *buf, size_t n, void *args);
+int drv_ps1_sio_write(const void *buf, size_t n,
+ const struct drv_event_done *done, void *args);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h
new file mode 100644
index 0000000..16b2bca
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h
@@ -0,0 +1,136 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_REGS_H
+#define DRV_PS1_SIO_REGS_H
+
+#include <stdint.h>
+
+struct sio_tx_data
+{
+ uint32_t value :8, :24;
+};
+
+struct sio_rx_data
+{
+ uint8_t values[4];
+};
+
+union sio_stat
+{
+ struct
+ {
+ uint32_t
+ tx_ready_started :1,
+ rx_fifo_not_empty :1,
+ tx_ready_finished :1,
+ rx_parity_error :1,
+ rx_fifo_overrun :1,
+ rx_bad_stp :1,
+ rx_inverted :1,
+ dsr :1,
+ cts :1,
+ irqreq :1,
+ :1,
+ baudrate :15, :6;
+ } bits;
+
+ uint32_t mask;
+};
+
+union sio_mode
+{
+ struct
+ {
+ uint16_t
+ baudrate_mul :2,
+ len :2,
+ parity_en :1,
+ parity_odd :1,
+ stplen :2,
+ :8;
+ } bits;
+
+ uint16_t mask;
+};
+
+union sio_ctrl
+{
+ struct
+ {
+ uint16_t
+ tx_en :1,
+ dtr :1,
+ rx_en :1,
+ tx_invert :1,
+ ack :1,
+ rts :1,
+ reset :1,
+ :1,
+ rx_int_mode :2,
+ tx_int_en :1,
+ rx_int_en :1,
+ dsr_int_en :1,
+ :3;
+ } bits;
+
+ uint16_t mask;
+};
+
+enum
+{
+ SIO_CTRL_RX_INT_1,
+ SIO_CTRL_RX_INT_2,
+ SIO_CTRL_RX_INT_3,
+ SIO_CTRL_RX_INT_4
+};
+
+enum
+{
+ SIO_MODE_FACTOR_STOP,
+ SIO_MODE_FACTOR_MUL1,
+ SIO_MODE_FACTOR_MUL16,
+ SIO_MODE_FACTOR_MUL64
+};
+
+enum
+{
+ SIO_MODE_LEN_5,
+ SIO_MODE_LEN_6,
+ SIO_MODE_LEN_7,
+ SIO_MODE_LEN_8
+};
+
+enum
+{
+ SIO_MODE_STP_RESERVED,
+ SIO_MODE_STP_1,
+ SIO_MODE_STP_1_5,
+ SIO_MODE_STP_2,
+};
+
+#define SIO_BASE 0x1f801050
+#define SIO_REG(n) (SIO_BASE + n)
+#define SIO_TX_DATA ((volatile struct sio_tx_data *)SIO_REG(0))
+#define SIO_RX_DATA ((const volatile struct sio_rx_data *)SIO_REG(0))
+#define SIO_STAT ((const volatile union sio_stat *)SIO_REG(4))
+#define SIO_MODE ((volatile union sio_mode *)SIO_REG(8))
+#define SIO_CTRL ((volatile union sio_ctrl *)SIO_REG(10))
+#define SIO_BAUD (*(volatile uint16_t *)SIO_REG(14))
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h
new file mode 100644
index 0000000..f5b97da
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_ROUTINES_H
+#define DRV_PS1_SIO_ROUTINES_H
+
+#include <drv/ps1/sio/types.h>
+
+int drv_ps1_sio_irq(void);
+int drv_ps1_sio_next(struct sio_fifo *f);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h
new file mode 100644
index 0000000..87dd412
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h
@@ -0,0 +1,65 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_TYPES_H
+#define DRV_PS1_SIO_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+
+struct sio_req
+{
+ union
+ {
+ struct sio_req_r
+ {
+ void *buf;
+ size_t n;
+ } r;
+
+ struct sio_req_w
+ {
+ const void *buf;
+ size_t n;
+ } w;
+ } u;
+
+ int (*f)(void);
+ struct drv_event_done done;
+ struct sio_req *next;
+};
+
+struct sio_fifo
+{
+ char buf[192];
+ size_t proc, pend;
+ struct sio_req *head, *tail;
+ int (*next)(void);
+};
+
+struct drv_ps1_sio
+{
+ bool init;
+ int event;
+ struct sio_fifo rx, tx;
+ struct drv_event ev;
+};
+
+extern struct drv_ps1_sio drv_ps1_sio;
+
+#endif
diff --git a/src/drv/ps1/sio/src/CMakeLists.txt b/src/drv/ps1/sio/src/CMakeLists.txt
new file mode 100644
index 0000000..1bcf5cf
--- /dev/null
+++ b/src/drv/ps1/sio/src/CMakeLists.txt
@@ -0,0 +1,29 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_sio PRIVATE
+ free.c
+ globals.c
+ init.c
+ irq.c
+ next.c
+ read.c
+ read_nb.c
+ update.c
+ write.c
+)
+
+target_link_libraries(drv_ps1_sio PRIVATE kprintf)
diff --git a/src/drv/ps1/sio/src/free.c b/src/drv/ps1/sio/src/free.c
new file mode 100644
index 0000000..5c506d0
--- /dev/null
+++ b/src/drv/ps1/sio/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+
+void drv_ps1_sio_free(struct drv_ps1_sio *const sio)
+{
+}
diff --git a/src/drv/ps1/sio/src/globals.c b/src/drv/ps1/sio/src/globals.c
new file mode 100644
index 0000000..35c72b8
--- /dev/null
+++ b/src/drv/ps1/sio/src/globals.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/types.h>
+
+struct drv_ps1_sio drv_ps1_sio;
diff --git a/src/drv/ps1/sio/src/init.c b/src/drv/ps1/sio/src/init.c
new file mode 100644
index 0000000..6bf44fc
--- /dev/null
+++ b/src/drv/ps1/sio/src/init.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+
+struct drv_ps1_sio *drv_ps1_sio_init(const struct drv_event *const ev)
+{
+ const unsigned long baudrate = 115200ul;
+
+ SIO_CTRL->bits.reset = 1;
+ SIO_BAUD = DRV_PS1_CPU_F / (16 * baudrate);
+ SIO_MODE->mask = (const union sio_mode)
+ {
+ .bits =
+ {
+ .baudrate_mul = SIO_MODE_FACTOR_MUL16,
+ .stplen = SIO_MODE_STP_1,
+ .len = SIO_MODE_LEN_8
+ }
+ }.mask;
+
+ SIO_CTRL->mask = (const union sio_ctrl)
+ {
+ .bits =
+ {
+ .rx_int_mode = SIO_CTRL_RX_INT_1,
+ .rx_int_en = 1,
+ .tx_en = 1,
+ .rx_en = 1,
+ .rts = 1,
+ .dtr = 1
+ }
+ }.mask;
+
+ static struct drv_ps1_irq_src src =
+ {
+ .mask = 1 << IRQ_SIO,
+ .fn = drv_ps1_sio_irq
+ };
+
+ if (drv_ps1_irq_set(&src))
+ return NULL;
+
+ I_MASK->bits.sio = 1;
+ drv_ps1_sio.ev = *ev;
+ return &drv_ps1_sio;
+}
diff --git a/src/drv/ps1/sio/src/irq.c b/src/drv/ps1/sio/src/irq.c
new file mode 100644
index 0000000..5a19d83
--- /dev/null
+++ b/src/drv/ps1/sio/src/irq.c
@@ -0,0 +1,71 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+
+int irq_sio_overrun;
+
+static int read_rx(struct sio_fifo *const f)
+{
+ const unsigned char v = *SIO_RX_DATA->values;
+ size_t n = f->pend + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ if (n == f->proc)
+ {
+ irq_sio_overrun = 1;
+ return -1;
+ }
+
+ f->buf[f->pend = n] = v;
+ return 0;
+}
+
+volatile unsigned sio_read;
+volatile int sw_overrun;
+
+int drv_ps1_sio_irq(void)
+{
+ SIO_CTRL->bits.rts = 0;
+
+ while (SIO_STAT->bits.rx_fifo_not_empty)
+ {
+ if (read_rx(&drv_ps1_sio.rx))
+ {
+ sw_overrun = 1;
+ break;
+ }
+
+ sio_read++;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_STAT->bits.sio = 0;
+ SIO_CTRL->bits.ack = 1;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/next.c b/src/drv/ps1/sio/src/next.c
new file mode 100644
index 0000000..4c330ab
--- /dev/null
+++ b/src/drv/ps1/sio/src/next.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int drv_ps1_sio_next(struct sio_fifo *const f)
+{
+ struct sio_req *const next = f->head->next;
+
+ free(f->head);
+
+ f->next = next ? next->f : NULL;
+ f->head = next;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/read.c b/src/drv/ps1/sio/src/read.c
new file mode 100644
index 0000000..e13ad29
--- /dev/null
+++ b/src/drv/ps1/sio/src/read.c
@@ -0,0 +1,125 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int load(void);
+
+static int check(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = f->head;
+ struct sio_req_r *const r = &req->u.r;
+
+ if (!r->n)
+ {
+ const struct drv_event_done *const d = &req->done;
+
+ if (d->f && d->f(SUCCESS, d->args))
+ return -1;
+
+ return drv_ps1_sio_next(f);
+ }
+
+ f->next = load;
+ return 0;
+}
+
+static void read_fifo(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = f->head;
+ struct sio_req_r *const r = &req->u.r;
+ char *p = r->buf;
+
+ I_MASK->bits.sio = 0;
+ SIO_CTRL->bits.rts = 0;
+
+ while (r->n)
+ {
+ if (f->pend == f->proc)
+ break;
+
+ size_t n = f->proc + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ *p++ = f->buf[f->proc = n];
+ r->buf = p;
+ r->n--;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_MASK->bits.sio = 1;
+}
+
+static int load(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req_r *const r = &f->head->u.r;
+
+ read_fifo(s);
+
+ if (!r->n)
+ f->next = check;
+
+ return 0;
+}
+
+int drv_ps1_sio_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = malloc(sizeof *req);
+
+ if (!req)
+ return -1;
+
+ *req = (const struct sio_req)
+ {
+ .f = load,
+ .done = *done,
+ .u.r =
+ {
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!f->head)
+ f->head = req;
+ else
+ f->tail->next = req;
+
+ f->tail = req;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/read_nb.c b/src/drv/ps1/sio/src/read_nb.c
new file mode 100644
index 0000000..755c5cf
--- /dev/null
+++ b/src/drv/ps1/sio/src/read_nb.c
@@ -0,0 +1,61 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/irq.h>
+#include <drv/ps1/bios.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+
+static int read_fifo(char *buf, size_t n)
+{
+ int ret = 0;
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+
+ I_MASK->bits.sio = 0;
+ SIO_CTRL->bits.rts = 0;
+
+ while (n)
+ {
+ if (f->pend == f->proc)
+ break;
+
+ size_t m = f->proc + 1;
+
+ if (m >= sizeof f->buf)
+ m = 0;
+
+ *buf++ = f->buf[f->proc = m];
+ n--;
+ ret++;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_MASK->bits.sio = 1;
+ return ret;
+}
+
+int drv_ps1_sio_read_nb(void *const buf, const size_t n, void *const args)
+{
+ return read_fifo(buf, n);
+}
diff --git a/src/drv/ps1/sio/src/update.c b/src/drv/ps1/sio/src/update.c
new file mode 100644
index 0000000..eac875c
--- /dev/null
+++ b/src/drv/ps1/sio/src/update.c
@@ -0,0 +1,98 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+static int init(struct drv_ps1_sio *const s)
+{
+ if (s->init)
+ return 0;
+
+ const struct drv_event *const ev = &s->ev;
+ static const struct drv_event_ops ops =
+ {
+ .read = drv_ps1_sio_read,
+ .read_nb = drv_ps1_sio_read_nb,
+ .write = drv_ps1_sio_write
+ };
+
+ if (ev->status("ttyS0", &ops, true, 0660, ev->args))
+ return -1;
+
+ s->init = true;
+ return 0;
+}
+
+static int rx(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->rx;
+
+ if (f->next)
+ return f->next();
+ else if (f->head)
+ f->next = f->head->f;
+
+ return 0;
+}
+
+static void write_tx(struct sio_fifo *const f)
+{
+ if (f->proc == f->pend)
+ return;
+
+ size_t n = f->proc + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ SIO_TX_DATA->value = f->buf[f->proc = n];
+}
+
+static int tx(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->tx;
+
+ if (SIO_STAT->bits.tx_ready_started)
+ write_tx(f);
+
+ if (f->next)
+ return f->next();
+ else if (f->head)
+ f->next = f->head->f;
+
+ return 0;
+}
+
+int drv_ps1_sio_update(struct drv_ps1_sio *const s)
+{
+ if (SIO_STAT->bits.rx_fifo_overrun)
+ SIO_CTRL->bits.ack = 1;
+
+ if (init(s) || rx(s) || tx(s))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/write.c b/src/drv/ps1/sio/src/write.c
new file mode 100644
index 0000000..942456f
--- /dev/null
+++ b/src/drv/ps1/sio/src/write.c
@@ -0,0 +1,117 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+static int store(void);
+
+static void write_fifo(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const r = f->head;
+ struct sio_req_w *const w = &r->u.w;
+ const char *p = w->buf;
+
+ while (w->n)
+ {
+ size_t n = f->pend + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+ else if (n == f->proc)
+ break;
+
+ f->buf[f->pend = n] = *p++;
+ w->buf = p;
+ w->n--;
+ }
+}
+
+static int check(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const r = f->head;
+ struct sio_req_w *const w = &r->u.w;
+
+ if (!w->n)
+ {
+ const struct drv_event_done *const d = &r->done;
+
+ if (d->f && d->f(SUCCESS, d->args))
+ return -1;
+
+ return drv_ps1_sio_next(f);
+ }
+
+ f->next = store;
+ return 0;
+}
+
+static int store(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req_w *const w = &f->head->u.w;
+
+ write_fifo(s);
+
+ if (!w->n)
+ f->next = check;
+
+ return 0;
+}
+
+int drv_ps1_sio_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const req = malloc(sizeof *req);
+
+ if (!req)
+ return -1;
+
+ *req = (const struct sio_req)
+ {
+ .f = store,
+ .done = *done,
+ .u.w =
+ {
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!f->head)
+ f->head = req;
+ else
+ f->tail->next = req;
+
+ f->tail = req;
+ return 0;
+}
diff --git a/src/drv/ps1/src/CMakeLists.txt b/src/drv/ps1/src/CMakeLists.txt
new file mode 100644
index 0000000..34042e3
--- /dev/null
+++ b/src/drv/ps1/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1 PRIVATE
+ free.c
+ init.c
+ update.c
+)
diff --git a/src/drv/ps1/src/free.c b/src/drv/ps1/src/free.c
new file mode 100644
index 0000000..62be1b1
--- /dev/null
+++ b/src/drv/ps1/src/free.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1.h>
+#include <drv/ps1/types.h>
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+
+void drv_ps1_free(struct drv_port *const p)
+{
+ drv_ps1_mc_free(p->mc);
+ drv_ps1_cd_free(p->cd);
+ drv_ps1_pad_free(p->pad);
+ drv_ps1_sio_free(p->sio);
+}
diff --git a/src/drv/ps1/src/init.c b/src/drv/ps1/src/init.c
new file mode 100644
index 0000000..8ee92a6
--- /dev/null
+++ b/src/drv/ps1/src/init.c
@@ -0,0 +1,59 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1.h>
+#include <drv/ps1/types.h>
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+#include <stdlib.h>
+
+struct drv_port *drv_ps1_init(const struct drv_event *const ev)
+{
+ struct drv_port *ret = NULL;
+ struct drv_ps1_mc *mc = NULL;
+ struct drv_ps1_cd *cd = NULL;
+ struct drv_ps1_pad *pad = NULL;
+ struct drv_ps1_sio *sio = NULL;
+
+ if (!(mc = drv_ps1_mc_init(ev))
+ || !(cd = drv_ps1_cd_init(ev))
+ || !(pad = drv_ps1_pad_init(ev))
+ || !(sio = drv_ps1_sio_init(ev))
+ || !(ret = malloc(sizeof *ret)))
+ goto failure;
+
+ *ret = (const struct drv_port)
+ {
+ .mc = mc,
+ .cd = cd,
+ .pad = pad,
+ .sio = sio
+ };
+
+ return ret;
+
+failure:
+ drv_ps1_mc_free(mc);
+ drv_ps1_cd_free(cd);
+ drv_ps1_pad_free(pad);
+ drv_ps1_sio_free(sio);
+ free(mc);
+ return NULL;
+}
diff --git a/src/drv/ps1/src/update.c b/src/drv/ps1/src/update.c
new file mode 100644
index 0000000..49b22bb
--- /dev/null
+++ b/src/drv/ps1/src/update.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1.h>
+#include <drv/ps1/types.h>
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+
+int drv_ps1_update(struct drv_port *const p)
+{
+ if (drv_ps1_mc_update(p->mc)
+ || drv_ps1_cd_update(p->cd)
+ || drv_ps1_pad_update(p->pad)
+ || drv_ps1_sio_update(p->sio))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/ps1/time/CMakeLists.txt b/src/drv/ps1/time/CMakeLists.txt
new file mode 100644
index 0000000..93c0143
--- /dev/null
+++ b/src/drv/ps1/time/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_time)
+add_subdirectory(src)
+target_include_directories(drv_ps1_time PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_time
+ PUBLIC c
+ PRIVATE drv drv_ps1_bios drv_ps1_irq drv_ps1_rcnt)
diff --git a/src/drv/ps1/time/include/drv/ps1/time.h b/src/drv/ps1/time/include/drv/ps1/time.h
new file mode 100644
index 0000000..f644b59
--- /dev/null
+++ b/src/drv/ps1/time/include/drv/ps1/time.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_TIME_H
+#define DRV_PS1_TIME_H
+
+int drv_ps1_time_tick(void);
+
+#endif
diff --git a/src/drv/ps1/time/private_include/drv/ps1/time/types.h b/src/drv/ps1/time/private_include/drv/ps1/time/types.h
new file mode 100644
index 0000000..2e673fb
--- /dev/null
+++ b/src/drv/ps1/time/private_include/drv/ps1/time/types.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_TIME_TYPES_H
+#define DRV_PS1_TIME_TYPES_H
+
+#include <time.h>
+
+extern volatile struct timespec drv_ps1_time;
+
+#endif
diff --git a/src/drv/ps1/time/src/CMakeLists.txt b/src/drv/ps1/time/src/CMakeLists.txt
new file mode 100644
index 0000000..d8ebf38
--- /dev/null
+++ b/src/drv/ps1/time/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_time PRIVATE
+ gettime.c
+ getres.c
+ globals.c
+ settime.c
+ tick.c
+)
diff --git a/src/drv/ps1/time/src/getres.c b/src/drv/ps1/time/src/getres.c
new file mode 100644
index 0000000..de69ff5
--- /dev/null
+++ b/src/drv/ps1/time/src/getres.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/time.h>
+#include <errno.h>
+#include <time.h>
+
+int drv_time_getres(const clockid_t id, struct timespec *const ts)
+{
+ if (id != CLOCK_REALTIME)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ else if (ts)
+ *ts = (const struct timespec){.tv_nsec = 1000000};
+
+ return 0;
+}
diff --git a/src/drv/ps1/time/src/gettime.c b/src/drv/ps1/time/src/gettime.c
new file mode 100644
index 0000000..0fdbfea
--- /dev/null
+++ b/src/drv/ps1/time/src/gettime.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/time.h>
+#include <drv/ps1/time/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/irq.h>
+#include <errno.h>
+#include <time.h>
+
+int drv_time_gettime(const clockid_t id, struct timespec *const ts)
+{
+ if (id != CLOCK_REALTIME)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ I_MASK->bits.tmr2 = 0;
+ *ts = drv_ps1_time;
+ I_MASK->bits.tmr2 = 1;
+ return 0;
+}
diff --git a/src/drv/ps1/time/src/globals.c b/src/drv/ps1/time/src/globals.c
new file mode 100644
index 0000000..2f53665
--- /dev/null
+++ b/src/drv/ps1/time/src/globals.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/time/types.h>
+#include <time.h>
+
+volatile struct timespec drv_ps1_time;
diff --git a/src/drv/ps1/time/src/settime.c b/src/drv/ps1/time/src/settime.c
new file mode 100644
index 0000000..f2ac5fe
--- /dev/null
+++ b/src/drv/ps1/time/src/settime.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/time.h>
+#include <drv/ps1/time/types.h>
+#include <drv/ps1/bios.h>
+#include <errno.h>
+#include <time.h>
+
+int drv_time_settime(const clockid_t id, const struct timespec *const ts)
+{
+ if (id != CLOCK_REALTIME)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ EnterCriticalSection();
+ drv_ps1_time = *ts;
+ ExitCriticalSection();
+ return 0;
+}
diff --git a/src/drv/ps1/time/src/tick.c b/src/drv/ps1/time/src/tick.c
new file mode 100644
index 0000000..494d8ed
--- /dev/null
+++ b/src/drv/ps1/time/src/tick.c
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/time.h>
+#include <drv/ps1/time/types.h>
+#include <drv/ps1/irq.h>
+#include <time.h>
+
+int drv_ps1_time_tick(void)
+{
+ int ret = 0;
+ struct timespec ts;
+ volatile struct timespec *const t = &drv_ps1_time;
+
+ if (clock_getres(CLOCK_REALTIME, &ts))
+ ret = -1;
+ else if (t->tv_nsec >= 1000000000 - ts.tv_nsec)
+ {
+ t->tv_sec++;
+ t->tv_nsec = 0;
+ }
+ else
+ t->tv_nsec += ts.tv_nsec;
+
+ I_STAT->bits.tmr2 = 0;
+ return ret;
+}
diff --git a/src/drv/src/CMakeLists.txt b/src/drv/src/CMakeLists.txt
new file mode 100644
index 0000000..e567c1c
--- /dev/null
+++ b/src/drv/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv PRIVATE
+ free.c
+ init.c
+ tree.c
+ update.c
+)
diff --git a/src/drv/src/free.c b/src/drv/src/free.c
new file mode 100644
index 0000000..2c324c0
--- /dev/null
+++ b/src/drv/src/free.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/tree.h>
+#include <drv/types.h>
+#include <stdlib.h>
+
+void drv_free(struct drv *const d)
+{
+ if (d)
+ for (size_t i = 0; i < d->n; i++)
+ drv_tree_free[i](d->ports[i]);
+
+ free(d);
+}
diff --git a/src/drv/src/init.c b/src/drv/src/init.c
new file mode 100644
index 0000000..4b89f15
--- /dev/null
+++ b/src/drv/src/init.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/types.h>
+#include <drv/tree.h>
+#include <drv/port.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv *drv_init(const struct drv_event *const ev)
+{
+ size_t init = 0;
+ struct drv *const ret = malloc(sizeof *ret);
+ struct drv_port **const ports = malloc(drv_tree_n * sizeof *ports);
+
+ if (!ports || !ret)
+ goto failure;
+
+ for (size_t i = 0; i < drv_tree_n; i++, init++)
+ {
+ struct drv_port *const p = drv_tree_init[i](ev);
+
+ if (!p)
+ goto failure;
+
+ ports[i] = p;
+ }
+
+ *ret = (const struct drv)
+ {
+ .ports = ports,
+ .n = drv_tree_n
+ };
+
+ return ret;
+
+failure:
+
+ if (ports)
+ for (size_t i = 0; i < init; i++)
+ drv_tree_free[i](ports[i]);
+
+ free(ports);
+ free(ret);
+ return NULL;
+}
diff --git a/src/drv/src/tree.c b/src/drv/src/tree.c
new file mode 100644
index 0000000..d52df3d
--- /dev/null
+++ b/src/drv/src/tree.c
@@ -0,0 +1,51 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/tree.h>
+#include <drv/tty.h>
+#include <drv/port.h>
+#include <stddef.h>
+
+struct drv_port *(*const drv_tree_init[])(const struct drv_event *) =
+{
+#if DRV_PS1
+ drv_ps1_init,
+#endif
+ drv_tty_init
+};
+
+enum {N = sizeof drv_tree_init / sizeof *drv_tree_init};
+
+int (*const drv_tree_update[N])(struct drv_port *) =
+{
+#if DRV_PS1
+ drv_ps1_update,
+#endif
+ drv_tty_update
+};
+
+void (*const drv_tree_free[N])(struct drv_port *) =
+{
+#if DRV_PS1
+ drv_ps1_free,
+#endif
+ drv_tty_free
+};
+
+const size_t drv_tree_n = N;
diff --git a/src/drv/src/update.c b/src/drv/src/update.c
new file mode 100644
index 0000000..268c2b6
--- /dev/null
+++ b/src/drv/src/update.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/tree.h>
+#include <drv/types.h>
+#include <drv/port.h>
+#include <stddef.h>
+
+int drv_update(struct drv *const d)
+{
+ for (size_t i = 0; i < drv_tree_n; i++)
+ if (drv_tree_update[i](d->ports[i]))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/tty/CMakeLists.txt b/src/drv/tty/CMakeLists.txt
new file mode 100644
index 0000000..ee14015
--- /dev/null
+++ b/src/drv/tty/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_tty)
+add_subdirectory(src)
+target_include_directories(drv_tty PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_tty PUBLIC c PRIVATE gfx drv_event)
diff --git a/src/drv/tty/include/drv/tty.h b/src/drv/tty/include/drv/tty.h
new file mode 100644
index 0000000..27804bf
--- /dev/null
+++ b/src/drv/tty/include/drv/tty.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_H
+#define DRV_TTY_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_tty_init(const struct drv_event *ev);
+int drv_tty_update(struct drv_port *p);
+void drv_tty_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/tty/private_include/drv/tty/font.h b/src/drv/tty/private_include/drv/tty/font.h
new file mode 100644
index 0000000..a36d68e
--- /dev/null
+++ b/src/drv/tty/private_include/drv/tty/font.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_FONT_H
+#define DRV_TTY_FONT_H
+
+#include <gfx/sprite.h>
+#include <stddef.h>
+
+struct gfx_sprite ttyfont_spr;
+extern const unsigned char ttyfont[];
+extern const size_t ttyfont_size;
+
+#endif
diff --git a/src/drv/tty/private_include/drv/tty/ops.h b/src/drv/tty/private_include/drv/tty/ops.h
new file mode 100644
index 0000000..b50b00a
--- /dev/null
+++ b/src/drv/tty/private_include/drv/tty/ops.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_OPS_H
+#define DRV_TTY_OPS_H
+
+#include <drv/event.h>
+#include <drv/tty/types.h>
+#include <stddef.h>
+
+int drv_tty_write(const void *buf, size_t n, const struct drv_event_done *done,
+ void *args);
+int drv_tty_setdim(struct drv_port *p, unsigned x, unsigned y);
+
+#endif
diff --git a/src/drv/tty/private_include/drv/tty/types.h b/src/drv/tty/private_include/drv/tty/types.h
new file mode 100644
index 0000000..38a1108
--- /dev/null
+++ b/src/drv/tty/private_include/drv/tty/types.h
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_TYPES_H
+#define DRV_TTY_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct row
+{
+ char *columns;
+ size_t len;
+};
+
+struct drv_port
+{
+ bool init;
+ struct row *rows, *first_row, *last_row, *proc_row;
+ size_t nrows, ncolumns, last_column, last_proc_column;
+ struct drv_event ev;
+};
+
+#endif
diff --git a/src/drv/tty/src/CMakeLists.txt b/src/drv/tty/src/CMakeLists.txt
new file mode 100644
index 0000000..096b685
--- /dev/null
+++ b/src/drv/tty/src/CMakeLists.txt
@@ -0,0 +1,27 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_tty PRIVATE
+ free.c
+ init.c
+ setdim.c
+ update.c
+ write.c
+)
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+endif()
diff --git a/src/drv/tty/src/free.c b/src/drv/tty/src/free.c
new file mode 100644
index 0000000..66d5cb4
--- /dev/null
+++ b/src/drv/tty/src/free.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void drv_tty_free(struct drv_port *const p)
+{
+ if (!p)
+ return;
+
+ for (size_t i = 0; i < p->nrows; i++)
+ free(p->rows[i].columns);
+
+ free(p->rows);
+ free(p);
+}
diff --git a/src/drv/tty/src/init.c b/src/drv/tty/src/init.c
new file mode 100644
index 0000000..53299f4
--- /dev/null
+++ b/src/drv/tty/src/init.c
@@ -0,0 +1,58 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int load(void *const buf, const size_t n, void *const args)
+{
+ size_t *const off = args;
+
+ memcpy(buf, ttyfont + *off, n);
+ *off += n;
+ return 0;
+}
+
+struct drv_port *drv_tty_init(const struct drv_event *const ev)
+{
+ size_t off = 0;
+ struct drv_port *ret = NULL;
+
+ if (!(ret = malloc(sizeof *ret)))
+ goto failure;
+
+ *ret = (const struct drv_port){.ev = *ev};
+ gfx_sprite_load(&ttyfont_spr, load, &off);
+
+ if (drv_tty_setdim(ret, screen_w, screen_h))
+ goto failure;
+
+ return ret;
+
+failure:
+ drv_tty_free(ret);
+ return NULL;
+}
diff --git a/src/drv/tty/src/ps1/CMakeLists.txt b/src/drv/tty/src/ps1/CMakeLists.txt
new file mode 100644
index 0000000..c07a45f
--- /dev/null
+++ b/src/drv/tty/src/ps1/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_tty PRIVATE
+ ttyfont_tim.c
+)
diff --git a/src/drv/tty/src/ps1/ttyfont_tim.c b/src/drv/tty/src/ps1/ttyfont_tim.c
new file mode 100644
index 0000000..b7dd03b
--- /dev/null
+++ b/src/drv/tty/src/ps1/ttyfont_tim.c
@@ -0,0 +1,801 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* Derived from res/font.bmp. See res/orig/LICENSE for details. */
+
+#include <drv/tty/font.h>
+#include <stddef.h>
+
+const unsigned char ttyfont[] = {
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x80, 0x02, 0xf2, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f,
+ 0x2c, 0x34, 0x3e, 0x26, 0xdc, 0x01, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x40, 0x5f, 0x1f, 0x36, 0x9c, 0x03, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x0c, 0x24, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00,
+ 0x30, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x10, 0x11, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x10, 0x00, 0x00, 0x01, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11,
+ 0x11, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x10, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x10, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x10, 0x01, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x10, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x10, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+const size_t ttyfont_size = sizeof ttyfont;
diff --git a/src/drv/tty/src/setdim.c b/src/drv/tty/src/setdim.c
new file mode 100644
index 0000000..d1f835a
--- /dev/null
+++ b/src/drv/tty/src/setdim.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int drv_tty_setdim(struct drv_port *const p, const unsigned w, const unsigned h)
+{
+ const unsigned columns = w / 10, rows = h / 16;
+ struct row *const prs = malloc(rows * sizeof *prs);
+
+ if (!prs)
+ goto failure;
+
+ for (unsigned i = 0; i < rows; i++)
+ *(prs + i) = (const struct row){0};
+
+ for (unsigned i = 0; i < rows; i++)
+ {
+ struct row *const p = &prs[i];
+ char *const c = malloc(columns);
+
+ if (!c)
+ goto failure;
+
+ p->columns = c;
+ }
+
+ p->first_row = p->last_row = p->proc_row = p->rows = prs;
+ p->nrows = rows;
+ p->ncolumns = columns;
+ return 0;
+
+failure:
+ for (unsigned i = 0; i < rows; i++)
+ free(prs[i].columns);
+
+ free(prs);
+ return -1;
+}
diff --git a/src/drv/tty/src/update.backup.c b/src/drv/tty/src/update.backup.c
new file mode 100644
index 0000000..d072977
--- /dev/null
+++ b/src/drv/tty/src/update.backup.c
@@ -0,0 +1,125 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .write = drv_tty_write,
+ .args = p
+ };
+
+ if (ev->status("tty", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+static short get_y(const struct drv_port *const p)
+{
+ const ptrdiff_t r = p->proc_row - p->first_row;
+
+ if (r >= 0)
+ return r * 16;
+
+ return (((p->rows + p->nrows) - p->first_row)
+ + (p->proc_row - p->rows)) * 16;
+}
+
+static int prepare(struct drv_port *const p)
+{
+ struct row *r = p->proc_row;
+
+ if (r == p->last_row)
+ return 0;
+ else if (!p->last_proc_column)
+ {
+ struct gfx_rect *const rect = gfx_rect_get();
+ const short y = get_y(p);
+
+ if (!rect)
+ return 0;
+
+ gfx_rect_init(rect);
+ rect->y = y;
+ rect->w = screen_w;
+ rect->h = 16;
+
+ if (gfx_rect_sort(rect))
+ return -1;
+ }
+
+ const char c = r->columns[p->last_proc_column];
+
+ if (c != ' ')
+ {
+ struct gfx_sprite *const s = gfx_sprite_get();
+
+ if (!s || gfx_sprite_clone(&ttyfont_spr, s))
+ return 0;
+
+ const short x = p->last_proc_column * 10, y = get_y(p);
+ const char ch = c - ' ';
+ const short u = (12 * ch) % ttyfont_spr.w;
+ const short v = 16 * ((12 * ch) / ttyfont_spr.w);
+
+ /* TODO: replace hardcoded values */
+ s->x = x;
+ s->y = y;
+ s->w = 12;
+ s->h = 16;
+ s->u += u;
+ s->v += v;
+
+ if (gfx_sprite_sort(s))
+ return -1;
+ }
+
+ if (++p->last_proc_column >= r->len)
+ {
+ if (++r - p->rows >= p->nrows)
+ r = p->rows;
+
+ p->last_proc_column = 0;
+ }
+
+ p->proc_row = r;
+ return 0;
+}
+
+int drv_tty_update(struct drv_port *const p)
+{
+ if (init(p) || prepare(p))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/tty/src/update.c b/src/drv/tty/src/update.c
new file mode 100644
index 0000000..7c01678
--- /dev/null
+++ b/src/drv/tty/src/update.c
@@ -0,0 +1,126 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .write = drv_tty_write,
+ .args = p
+ };
+
+ if (ev->status("tty", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+static short get_y(const struct drv_port *const p)
+{
+ const ptrdiff_t r = p->proc_row - p->first_row;
+
+ if (r >= 0)
+ return r * 16;
+
+ return (((p->rows + p->nrows) - p->first_row)
+ + (p->proc_row - p->rows)) * 16;
+}
+
+static int prepare(struct drv_port *const p)
+{
+ struct row *r = p->proc_row;
+
+ if (r == p->last_row)
+ return 0;
+
+ struct gfx_rect *const rect = gfx_rect_get();
+ const short y = get_y(p);
+ short x = 0;
+
+ if (!rect)
+ return 0;
+
+ gfx_rect_init(rect);
+ rect->y = y;
+ rect->w = screen_w;
+ rect->h = 16;
+
+ if (gfx_rect_sort(rect))
+ return -1;
+
+ /* TODO: this is a trick to avoid having half-rendered lines. */
+ struct gfx_sprite *sprites[64];
+
+ for (size_t i = 0; i < sizeof sprites / sizeof *sprites; i++)
+ sprites[i] = gfx_sprite_get();
+
+ for (const char *c = r->columns;
+ *c && c - r->columns < p->ncolumns; c++, x += 10)
+ {
+ struct gfx_sprite *const s = sprites[c - r->columns];
+
+ if (*c == ' ')
+ continue;
+
+ const char ch = *c - ' ';
+ const short u = (12 * ch) % ttyfont_spr.w;
+ const short v = 16 * ((12 * ch) / ttyfont_spr.w);
+
+ if (!s || gfx_sprite_clone(&ttyfont_spr, s))
+ return 0;
+
+ /* TODO: replace hardcoded values */
+ s->x = x;
+ s->y = y;
+ s->w = 12;
+ s->h = 16;
+ s->u += u;
+ s->v += v;
+
+ if (gfx_sprite_sort(s))
+ return -1;
+ }
+
+ if (++r - p->rows >= p->nrows)
+ r = p->rows;
+
+ p->proc_row = r;
+ return 0;
+}
+
+int drv_tty_update(struct drv_port *const p)
+{
+ if (init(p) || prepare(p))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/tty/src/write.c b/src/drv/tty/src/write.c
new file mode 100644
index 0000000..d4a988d
--- /dev/null
+++ b/src/drv/tty/src/write.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/types.h>
+#include <drv/tty/ops.h>
+#include <errno.h>
+#include <stddef.h>
+
+int drv_tty_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const d, void *const args)
+{
+ struct drv_port *const p = args;
+
+ for (const char *s = buf; s - (const char *)buf < n; s++)
+ {
+ struct row *const r = p->last_row;
+ char *const col = &r->columns[p->last_column];
+
+ if (*s == '\r')
+ {
+ *col = '\0';
+ p->last_column = r->len = 0;
+ }
+ else
+ {
+ if (*s != '\n')
+ {
+ *col = *s;
+ r->len++;
+ }
+ else
+ *col = '\0';
+
+ if (*s == '\n' || ++p->last_column >= p->ncolumns)
+ {
+ if (++p->last_row - p->rows >= p->nrows)
+ p->last_row = p->rows;
+
+ if (p->last_row == p->first_row)
+ {
+ if (++p->first_row - p->rows >= p->nrows)
+ p->first_row = p->rows;
+
+ p->proc_row = p->first_row;
+ }
+
+ p->last_column = 0;
+ }
+ }
+ }
+
+ return d->f(SUCCESS, d->args);
+}