From 819a3145082994603efd00498c7bb883e26403db Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sat, 9 Nov 2024 18:09:09 +0100 Subject: [PATCH] Apple2: Rewrite opendir in assembly 58 bytes size gain --- libsrc/apple2/dir.inc | 15 ++++ libsrc/apple2/opendir.c | 112 ----------------------------- libsrc/apple2/opendir.s | 156 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 112 deletions(-) create mode 100644 libsrc/apple2/dir.inc delete mode 100644 libsrc/apple2/opendir.c create mode 100644 libsrc/apple2/opendir.s diff --git a/libsrc/apple2/dir.inc b/libsrc/apple2/dir.inc new file mode 100644 index 000000000..afad44eb7 --- /dev/null +++ b/libsrc/apple2/dir.inc @@ -0,0 +1,15 @@ +.struct DIR + FD .word + ENTRY_LENGTH .byte + ENTRIES_PER_BLOCK .byte + CURRENT_ENTRY .byte + + .union + BYTES .byte 512 + .struct CONTENT + PREV_BLOCK .word + NEXT_BLOCK .word + ENTRIES .byte + .endstruct + .endunion +.endstruct diff --git a/libsrc/apple2/opendir.c b/libsrc/apple2/opendir.c deleted file mode 100644 index 1144d8511..000000000 --- a/libsrc/apple2/opendir.c +++ /dev/null @@ -1,112 +0,0 @@ -/*****************************************************************************/ -/* */ -/* opendir.h */ -/* */ -/* Open a directory */ -/* */ -/* */ -/* */ -/* (C) 2005 Oliver Schmidt, */ -/* */ -/* */ -/* This software is provided 'as-is', without any expressed or implied */ -/* warranty. In no event will the authors be held liable for any damages */ -/* arising from the use of this software. */ -/* */ -/* Permission is granted to anyone to use this software for any purpose, */ -/* including commercial applications, and to alter it and redistribute it */ -/* freely, subject to the following restrictions: */ -/* */ -/* 1. The origin of this software must not be misrepresented; you must not */ -/* claim that you wrote the original software. If you use this software */ -/* in a product, an acknowledgment in the product documentation would be */ -/* appreciated but is not required. */ -/* 2. Altered source versions must be plainly marked as such, and must not */ -/* be misrepresented as being the original software. */ -/* 3. This notice may not be removed or altered from any source */ -/* distribution. */ -/* */ -/*****************************************************************************/ - - - -#include -#include -#include -#include -#include -#include -#include -#include "dir.h" - - - -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -extern char _cwd[FILENAME_MAX]; - - - -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ - - - -DIR* __fastcall__ opendir (register const char* name) -{ - register DIR* dir; - - /* Alloc DIR */ - if ((dir = malloc (sizeof (*dir))) == NULL) { - - /* May not have been done by malloc() */ - _directerrno (ENOMEM); - - /* Return failure */ - return NULL; - } - - /* Interpret dot as current working directory */ - if (*name == '.') { - name = _cwd; - } - - /* Open directory file */ - if ((dir->fd = open (name, O_RDONLY)) != -1) { - - /* Read directory key block */ - if (read (dir->fd, - dir->block.bytes, - sizeof (dir->block)) == sizeof (dir->block)) { - - /* Get directory entry infos from directory header */ - dir->entry_length = dir->block.bytes[0x23]; - dir->entries_per_block = dir->block.bytes[0x24]; - - /* Skip directory header entry */ - dir->current_entry = 1; - - /* Return success */ - return dir; - } - - /* EOF: Most probably no directory file at all */ - if (_oserror == 0) { - _directerrno (EINVAL); - } - - /* Cleanup directory file */ - close (dir->fd); - } - - /* Cleanup DIR */ - free (dir); - - /* Return failure */ - return NULL; -} diff --git a/libsrc/apple2/opendir.s b/libsrc/apple2/opendir.s new file mode 100644 index 000000000..b75b83636 --- /dev/null +++ b/libsrc/apple2/opendir.s @@ -0,0 +1,156 @@ +; +; Colin Leroy-Mira , 2024 +; +; DIR* __fastcall__ opendir (register const char* name) +; + + .export _opendir + + .import _open, _read, _close + .import _malloc, _free + .import ___directerrno + + .import ___oserror, __cwd + + .import pushptr1, popptr1 + .import pushax, pusha0 + + .importzp ptr1 + + .include "apple2.inc" + .include "dir.inc" + .include "errno.inc" + .include "fcntl.inc" + .include "zeropage.inc" + +.proc _opendir + sta ptr1 + stx ptr1+1 + + ldy #$00 + lda (ptr1),y + cmp #'.' + bne :+ + + lda #<__cwd + ldx #>__cwd + sta ptr1 + stx ptr1+1 + +: ; open directory + jsr pushptr1 + lda #O_RDONLY + jsr pusha0 + + ldy #$04 + jsr _open + + cmp #$FF ; Did we succeed? + beq @return_null + pha ; Yes - Push fd for backup + + ; malloc the dir struct + lda #<.sizeof(DIR) + ldx #>.sizeof(DIR) + jsr _malloc + bne :+ + + ; We failed to allocate + pla ; Get fd back + ldx #$00 + jsr _close ; close it + + lda #ENOMEM ; Set error + jsr ___directerrno + +@return_null: + lda #$00 + tax + rts + +: ; Store dir struct to pointer + sta ptr1 + stx ptr1+1 + + ; Push ptr1, read will destroy it + jsr pushptr1 + + ; Save fd to dir struct + lda #$00 + ldy #DIR::FD + 1 + sta (ptr1),y + + dey + pla ; Get fd back + sta (ptr1),y + + jsr pusha0 ; push fd for read + lda #DIR::BYTES + adc ptr1+1 + tax + pla + jsr pushax ; Push dir->block.bytes for read + + lda #<.sizeof(DIR::BYTES) + ldx #>.sizeof(DIR::BYTES) + + jsr _read ; Read directory block + cpx #>.sizeof(DIR::BYTES) + bne @err_read + cmp #<.sizeof(DIR::BYTES) + beq @read_ok + +@err_read: + ; Read failed, exit + lda ___oserror + bne :+ + lda #EINVAL + jsr ___directerrno + +: ; Close fd + jsr popptr1 ; Restore our dir pointer + ldy #$00 + lda (ptr1),y ; Get fd + ldx #$00 + jsr _close + + ; Free dir structure + lda ptr1 + ldx ptr1+1 + jsr _free + jmp @return_null + +@read_ok: + ; Read succeeded, populate dir struct + jsr popptr1 ; Restore our dir pointer + + ldy #$24 + DIR::BYTES + lda (ptr1),y ; ENTRIES_PER_BLOCK + pha ; Back it up + + dey + lda (ptr1),y ; ENTRY_LENGTH + + ldy #DIR::ENTRY_LENGTH + sta (ptr1),y + + pla + .assert DIR::ENTRIES_PER_BLOCK = DIR::ENTRY_LENGTH + 1, error + iny + sta (ptr1),y + + ; Skip directory header entry + .assert DIR::CURRENT_ENTRY = DIR::ENTRIES_PER_BLOCK + 1, error + iny + lda #$01 + sta (ptr1),y + + ; Return pointer to dir struct + lda ptr1 + ldx ptr1+1 + rts +.endproc