{"id":50679215,"url":"https://github.com/gerph/riscos-libasm","last_synced_at":"2026-06-08T17:32:13.835Z","repository":{"id":356627628,"uuid":"1233386923","full_name":"gerph/riscos-libasm","owner":"gerph","description":"LibAsm for RISC OS (assembly routines to avoid having to re-write them)","archived":false,"fork":false,"pushed_at":"2026-05-08T22:59:32.000Z","size":36,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-09T00:34:49.953Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gerph.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T22:50:51.000Z","updated_at":"2026-05-08T22:55:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gerph/riscos-libasm","commit_stats":null,"previous_names":["gerph/riscos-libasm"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/gerph/riscos-libasm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerph%2Friscos-libasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerph%2Friscos-libasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerph%2Friscos-libasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerph%2Friscos-libasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gerph","download_url":"https://codeload.github.com/gerph/riscos-libasm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerph%2Friscos-libasm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34073776,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-08T17:32:12.918Z","updated_at":"2026-06-08T17:32:13.827Z","avatar_url":"https://github.com/gerph.png","language":"Assembly","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LibAsm for RISC OS\n\nThis is a collection of RISC OS assembly functions which are intended to\nabstract the functionality so that C code doesn't have to care about\nhow things are implemented, just that it can call them.\n\n\n## Installation and Usage\n\n### Linking in a Makefile\n\nTo use libAsm, add it to the `LIBS` variable in your `Makefile,fe1`:\n\n```makefile\nLIBS = ${CLIB} C:Asm.o.libAsm\n```\n\nNote: `Asm.o.libAsm` (32-bit) are available. The 64-bit variant is not available.\n\n### Including Headers in C Code\n\nInclude the relevant headers in your C source files using the `Asm/` prefix:\n\n```c\n#include \"Asm/muldiv.h\"      /* Multiplication and division */\n#include \"Asm/processor.h\"   /* Processor identification */\n#include \"Asm/irqs.h\"        /* IRQ control */\n#include \"Asm/fpsvc.h\"       /* Floating-point preservation */\n#include \"Asm/callx.h\"       /* Cross-mode function calls */\n#include \"Asm/callbacks.h\"   /* Triggering callbacks */\n#include \"Asm/starttasksvc.h\"/* Wimp_StartTask from SVC mode */\n```\n\n## Available Routines\n\n### Multiplication and Division (`Asm/muldiv.h`)\n\nThe `muldiv()` function performs `(a * b) / c` with a 64-bit intermediate product,\navoiding overflow that would occur with standard 32-bit multiplication.\n\n```c\n#include \"Asm/muldiv.h\"\n\nint result = muldiv(100, 200, 50);  /* Returns (100 * 200) / 50 = 400 */\n```\n\n**Why use muldiv?** Standard C multiplication of two 32-bit values can overflow before\ndivision. The `muldiv` function performs the calculation internally using 64-bit arithmetic\nto preserve precision.\n\n### Processor Identification (`Asm/processor.h`)\n\n`processor_id()` returns the ARM processor ID register value, which encodes the processor\ntype, architecture, and revision.\n\n```c\n#include \"Asm/processor.h\"\n\nunsigned long id = processor_id();\n```\n\nThe header provides macros to interpret the processor ID:\n\n| Macro | Description |\n|-------|-------------|\n| `processor_architecture(id)` | Returns an `procarch_t` enum value for the architecture |\n| `processor_is_arm6x0(id)` | Non-zero if running on an ARM6x0 series processor |\n| `processor_is_arm7(id)` | Non-zero if running on an ARM7 series processor |\n\nArchitecture enum values:\n\n| Enum | Architecture |\n|------|-------------|\n| `arch_2` | ARM2/ARM3 |\n| `arch_3` | ARM6/ARM60 |\n| `arch_4` | ARM7500-style (Architecture 4) |\n| `arch_4T` | ARM7TDMI (Architecture 4T) |\n| `arch_5` | StrongARM (Architecture 5) |\n| `arch_5T` | Architecture 5T |\n| `arch_5TE` | Architecture 5TE |\n| `arch_5TEJ` | Architecture 5TEJ |\n| `arch_6` | Architecture 6 |\n\n### IRQ Control (`Asm/irqs.h`)\n\nThese functions safely manipulate the interrupt mask bits in the processor mode register.\n\n```c\n#include \"Asm/irqs.h\"\n\nunsigned long flags;\n\nflags = ensure_irqs_off();   /* Disable IRQs, save previous state */\n/* Critical section */\nrestore_irqs(flags);         /* Restore previous state */\n\nflags = ensure_irqs_on();    /* Enable IRQs, save previous state */\n/* Section where IRQs must be on */\nrestore_irqs(flags);         /* Restore previous state */\n```\n\n**Why use these?** Direct manipulation of the SPSR or CPSR is error-prone. These functions\nprovide a structured way to disable/enable interrupts while preserving the previous state,\nwhich is essential for interrupt handlers and critical section code.\n\n### Floating-Point Preservation (`Asm/fpsvc.h`)\n\nWhen using floating-point operations in SVC mode (e.g., from a Wimp filter), the FPU\nregisters must be preserved because the APCS declares F0-F3 as corruptible.\n\n```c\n#include \"Asm/fpsvc.h\"\n\nvoid my_svc_function(void) {\n    int result;\n    fpsvc_buf fpbuf;\n    fpsvc_preserve(\u0026fpbuf);\n\n    /* Do floating-point operations here */\n    result = calculate_value(3.14159);\n\n    fpsvc_restore(\u0026fpbuf);\n}\n```\n\n**Why use this?** Without preserving FPU state, your code may corrupt the floating-point\ncontext of the task that called your SVC-mode code, leading to incorrect calculations or\ncrashes in the calling application.\n\n### Non-C Function Calls (`Asm/callx.h`)\n\n`_callx()` allows you to call an arbitrary function with register arguments, similar to\n`_swix()` but for function calls rather than SWIs.\n\n```c\n#include \"Asm/callx.h\"\n#include \"swis.h\"\n\n/* Call a function with R0-R4 as arguments, R0 as output */\nvoid *func_ptr = some_function;\nvoid *func_pw = module_pw;\nint result;\n\n/* Mask format: bits 0-11 = input registers: `_IN(reg)` and `_INR(loreg,hireg)`\n                bits 22-31 = output registers: `_OUT(reg)` and `_OUTR(loreg,hireg)` */\nint result;\n_callx(func_ptr, func_pw, _INR(0,4)|_OUT(0), arg0, arg1, arg2, arg3, arg4,\n       \u0026result);\n```\n\n**Why use `_callx`?** When you need to call a function (e.g., a registered handler\n), `_callx` provides a clean interface for passing arguments and receiving\nresults, similar to how `_swix` works for SWIs.\n\n### Callback Triggering (`Asm/callbacks.h`)\n\n`trigger_callbacks()` drops to user mode to allow pending callbacks to be processed.\n\n```c\n#include \"Asm/callbacks.h\"\n\n/* During a long-running operation */\nfor (int i = 0; i \u003c 1000; i++) {\n    do_work_step(i);\n    if ((i % 100) == 0) {\n        trigger_callbacks();  /* Allow Wimp tasks and callbacks */\n    }\n}\n```\n\n**Why use this?** Long-running code in SVC mode can prevent the Wimp from processing\ncallbacks (e.g., TaskWindow events, mouse movements). Dropping to user mode briefly\nallows the system to update and respond to user input.\n\n### Wimp_StartTask from SVC (`Asm/starttasksvc.h`)\n\n`svc_wimp_start_task()` safely calls `Wimp_StartTask` from SVC mode by dropping to USR\nmode first.\n\n```c\n#include \"Asm/starttasksvc.h\"\n\nunsigned long taskhandle = svc_wimp_start_task(\"SWidget swidget\", 0);\nif (taskhandle != 0) {\n    /* Task started successfully */\n}\n```\n\n**Why use this?** `Wimp_StartTask` cannot be called directly from SVC mode because it\ntriggers a task switch. This function handles the mode switch correctly and returns the\ntask handle without corrupting the USR mode stack.\n\n## Common Patterns\n\n### Safe Critical Section with IRQ Control\n\n```c\n#include \"Asm/irqs.h\"\n\nvoid update_shared_data(void) {\n    unsigned long flags = ensure_irqs_off();\n\n    /* Atomic update of shared data structure */\n    shared_counter++;\n    shared_flag = TRUE;\n\n    restore_irqs(flags);\n}\n```\n\n### Architecture-Specific Code\n\n```c\n#include \"Asm/processor.h\"\n\nvoid init_hardware(void) {\n    unsigned long id = processor_id();\n\n    switch (processor_architecture(id)) {\n        case arch_4:\n        case arch_4T:\n            init_arm7_hardware();\n            break;\n        case arch_5:\n        case arch_5T:\n        case arch_5TE:\n            init_strongarm_hardware();\n            break;\n        default:\n            init_generic_hardware();\n            break;\n    }\n}\n```\n\n### Floating-Point in a SWI call\n\n```c\n#include \"kernel.h\"\n#include \"Asm/fpsvc.h\"\n\n_kernel_oserror *my_filter(_kernel_swi_regs *r, void *wb) {\n    fpsvc_buf fpbuf;\n    fpsvc_preserve(\u0026fpbuf);\n\n    /* Use floating-point calculations */\n    float scale = 1.5f;\n    float value = compute_value() * scale;\n\n    fpsvc_restore(\u0026fpbuf);\n    return NULL;\n}\n```\n\n### Long-Running Operation with Callbacks\n\n```c\n#include \"Asm/callbacks.h\"\n\nvoid process_large_file(void) {\n    for (int block = 0; block \u003c total_blocks; block++) {\n        process_block(block);\n\n        /* Allow callbacks every 100 blocks */\n        if ((block % 100) == 0) {\n            trigger_callbacks();\n        }\n    }\n}\n```\n\n## Build Notes\n\n* The library is only available for 32-bit builds. There is no 64-bit variant.\n    * The `_callx` implementation is already present in the 64-bit C library.\n* The standard variant (`libAsm`) is for application use.\n* The module variant (`libAsmzm`) is position-independent and safe for ROM inclusion.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerph%2Friscos-libasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgerph%2Friscos-libasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerph%2Friscos-libasm/lists"}