Merge branch 'cc65:master' into master

This commit is contained in:
rumbledethumps
2024-01-29 08:45:56 -08:00
committed by GitHub
94 changed files with 2888 additions and 1067 deletions

20
libsrc/apple2/beep.s Normal file
View File

@@ -0,0 +1,20 @@
;
; Colin Leroy-Mira, 2024
;
; void beep(void)
;
.export _beep
.import BELL
.include "apple2.inc"
.segment "LOWCODE"
_beep:
lda CH ; Bell scrambles CH in 80col mode on IIgs, storing
pha ; it in OURCH and resetting CH to 0. Save it.
jsr BELL
pla
sta CH ; Restore CH
rts

20
libsrc/apple2/bell.s Normal file
View File

@@ -0,0 +1,20 @@
;
; Colin Leroy-Mira, 2024
;
; BELL routine
;
.export BELL
.include "apple2.inc"
.segment "LOWCODE"
BELL:
; Switch in ROM and call BELL
bit $C082
jsr $FF3A ; BELL
; Switch in LC bank 2 for R/O and return
bit $C080
rts

View File

@@ -40,12 +40,15 @@ _exit: ldx #<exit
lda #>exit
jsr reset ; Setup RESET vector
; Switch in ROM, in case it wasn't already switched in by a RESET.
bit $C082
; Switch in LC bank 2 for R/O in case it was switched out by a RESET.
bit $C080
; Call the module destructors.
jsr donelib
; Switch in ROM.
bit $C082
; Restore the original RESET vector.
exit: ldx #$02
: lda rvsave,x

View File

@@ -0,0 +1,17 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; void __fastcall__ detect_iigs(void)
;
.export _detect_iigs
.import ostype, return0, return1
.include "apple2.inc"
; Returns 1 if running on IIgs, 0 otherwise
_detect_iigs:
lda ostype
bpl :+
jmp return1
: jmp return0

View File

@@ -0,0 +1,22 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; unsigned char __fastcall__ get_iigs_speed(void)
;
.export _get_iigs_speed
.import ostype, return0
.include "apple2.inc"
.include "accelerator.inc"
_get_iigs_speed:
lda ostype ; Return SLOW if not IIgs
bpl :+
lda CYAREG ; Check current setting
bpl :+
lda #SPEED_FAST
ldx #$00
rts
.assert SPEED_SLOW = 0, error
: jmp return0 ; SPEED_SLOW

View File

@@ -5,7 +5,7 @@
;
.constructor initostype, 9
.export _get_ostype
.export _get_ostype, ostype
; Identify machine according to:
; Apple II Miscellaneous TechNote #7, Apple II Family Identification

View File

@@ -0,0 +1,29 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; unsigned char __fastcall__ detect_iigs(unsigned char speed)
;
.export _set_iigs_speed
.import ostype, return0
.include "apple2.inc"
.include "accelerator.inc"
_set_iigs_speed:
tax ; Keep parameter
lda ostype ; Return if not IIgs
bmi :+
jmp return0
: lda CYAREG
cpx #SPEED_SLOW
beq :+
ora #%10000000
bne set_speed
: and #%01111111
set_speed:
sta CYAREG
txa
ldx #$00
rts

54
libsrc/apple2/sleep.s Normal file
View File

@@ -0,0 +1,54 @@
;
; Colin Leroy-Mira <colin@colino.net>, 2024
;
; void __fastcall__ sleep(unsigned s)
;
;
.export _sleep
.import _get_iigs_speed
.import _set_iigs_speed
.import WAIT
.importzp tmp1
.include "accelerator.inc"
; This functions uses the Apple2 WAIT ROM routine to waste a certain
; amount of cycles and returns approximately after the numbers of
; seconds passed in AX.
;
; It takes 1023730 cycles when called with AX=1 (1,0007s),
; 10236364 cycles when called with AX=10 (10,006 seconds),
; 306064298 cycles with AX=300 (299.2 seconds).
;
; Caveat: IRQs firing during calls to sleep will make the sleep longer
; by the amount of cycles it takes to handle the IRQ.
;
_sleep:
stx tmp1 ; High byte of s in X
tay ; Low byte in A
ora tmp1
bne :+
rts
: jsr _get_iigs_speed ; Save current CPU speed
pha
lda #SPEED_SLOW ; Down to 1MHz for consistency around WAIT
jsr _set_iigs_speed
sleep_1s:
ldx #$0A ; Loop 10 times
sleep_100ms:
lda #$C7 ; Sleep about 99ms
jsr WAIT
lda #$0D ; About 1ms
jsr WAIT
dex
bne sleep_100ms
dey
bne sleep_1s
dec tmp1
bmi done
dey ; Down to #$FF
bne sleep_1s
done:
pla ; Restore CPU speed
jmp _set_iigs_speed

View File

@@ -6,7 +6,7 @@
.export _statvfs
.import _dio_query_sectsize
.import mli_file_info, pushax, popax, popptr1
.import mli_file_info, pushax, popax, popptr1, pushptr1
.include "zeropage.inc"
.include "apple2.inc"
.include "errno.inc"
@@ -45,9 +45,7 @@ _statvfs:
sty vol_sep ; Register '/' index
lda #$00
sta (ptr1),y ; Cut pathname at first slash
: lda ptr1
ldx ptr1+1
jsr pushax
: jsr pushptr1
jsr mli_file_info

20
libsrc/apple2/wait.s Normal file
View File

@@ -0,0 +1,20 @@
;
; Colin Leroy-Mira, 2024
;
; WAIT routine
;
.export WAIT
.include "apple2.inc"
.segment "LOWCODE"
WAIT:
; Switch in ROM and call WAIT
bit $C082
jsr $FCA8 ; Vector to WAIT routine
; Switch in LC bank 2 for R/O and return
bit $C080
rts

View File

@@ -5,21 +5,11 @@
;
.ifdef __APPLE2ENH__
.constructor initvsync
.export _waitvsync
.import _get_ostype
.import ostype
.include "apple2.inc"
.segment "ONCE"
initvsync:
jsr _get_ostype
sta ostype
rts
.code
_waitvsync:
bit ostype
bmi iigs ; $8x
@@ -53,8 +43,4 @@ iic: sei
cli
rts
.segment "INIT"
ostype: .res 1
.endif ; __APPLE2ENH__

View File

@@ -19,7 +19,7 @@
.import findfreeiocb
.import incsp4
.import ldaxysp,addysp
.import ___oserror
.import ___oserror, returnFFFF
.ifdef UCASE_FILENAME
.import ucase_fn
.endif
@@ -39,9 +39,7 @@ parmok: jsr findfreeiocb
lda #<EMFILE ; "too many open files"
seterr: jsr ___directerrno
jsr incsp4 ; clean up stack
lda #$FF
tax
rts ; return -1
jmp returnFFFF
; process the mode argument

View File

@@ -40,7 +40,7 @@
.export _cbm_read
.importzp ptr1, ptr2, ptr3, tmp1
.import popax, popa
.import popax, popa, returnFFFF
.import ___oserror
@@ -107,7 +107,4 @@ _cbm_read:
; CHKIN failed
@E1: sta ___oserror
lda #$FF
tax
rts ; return -1
jmp returnFFFF

View File

@@ -32,7 +32,7 @@
.export _cbm_write
.importzp ptr1, ptr2, ptr3
.import popax, popa
.import popax, popa, returnFFFF
.import ___oserror
@@ -88,7 +88,4 @@ _cbm_write:
; Error entry, error code is in A
@E2: sta ___oserror
lda #$FF
tax
rts ; return -1
jmp returnFFFF

View File

@@ -1,22 +0,0 @@
/*
** _is_leap_year.h
**
** (C) Copyright 2024, Colin Leroy-Mira <colin@colino.net>
**
*/
#ifndef __IS_LEAP_YEAR_H
#define __IS_LEAP_YEAR_H
unsigned char __fastcall__ IsLeapYear (unsigned char Year);
/* Returns 1 if the given year is a leap year. Expects a year from 0 to 206,
* without 1900 added */
/* End of _is_leap_year.h */
#endif

View File

@@ -1,23 +0,0 @@
;
; Colin Leroy-Mira, 2024
;
; unsigned char __fastcall__ IsLeapYear (unsigned char Year)
; Returns 1 in A if the given year is a leap year. Expects a year from 0 to 206,
; without 1900 added.
;
.export _IsLeapYear
_IsLeapYear:
ldx #$00 ; Prepare X for rts
cmp #$00 ; Y 0 (1900) is not a leap year
beq NotLeap
cmp #$C8 ; Y 200 (2100) is not a leap year
beq NotLeap
and #$03 ; Year % 4 == 0 means leap year
bne NotLeap
lda #$01 ; Return 1
rts
NotLeap:
lda #$00 ; Return 0
rts

View File

@@ -1,64 +0,0 @@
/*****************************************************************************/
/* */
/* gmtime.c */
/* */
/* Convert calendar time into broken down time in UTC */
/* */
/* */
/* */
/* (C) 2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* 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 <time.h>
/*****************************************************************************/
/* Code */
/*****************************************************************************/
struct tm* __fastcall__ _time_t_to_tm (const time_t t)
{
static struct tm timebuf;
/* Since our ints are just 16 bits, split the given time into seconds,
** hours and days. Each of the values will fit in a 16 bit variable.
** The mktime routine will then do the rest.
*/
timebuf.tm_sec = t % 3600;
timebuf.tm_min = 0;
timebuf.tm_hour = (t / 3600) % 24;
timebuf.tm_mday = (t / (3600UL * 24UL)) + 1;
timebuf.tm_mon = 0;
timebuf.tm_year = 70; /* Base value is 1/1/1970 */
/* Call mktime to do the final conversion */
mktime (&timebuf);
/* Return the result */
return &timebuf;
}

View File

@@ -0,0 +1,129 @@
;
; Colin Leroy-Mira, 2024
;
; struct tm* __fastcall__ _time_t_to_tm (const time_t t)
;
; Helper to gmtime and localtime. Breaks down a number of
; seconds since Jan 1, 1970 into days, hours and seconds,
; so that each of them fits in 16 bits; passes the
; result to _mktime which fixes all values in the struct,
; and returns a pointer to the struct to callers.
;
.export __time_t_to_tm
.import udiv32, _mktime
.importzp sreg, tmp3, ptr1, ptr2, ptr3, ptr4
.include "time.inc"
.macpack cpu
__time_t_to_tm:
; Divide number of seconds since epoch, in ptr1:sreg,
; by 86400 to get the number of days since epoch, and
; the number of seconds today in the remainder.
; Load t as dividend (sreg is already set by the caller)
sta ptr1
stx ptr1+1
; Load 86400 as divisor
lda #$80
sta ptr3
lda #$51
sta ptr3+1
lda #$01
sta ptr4
lda #$00
sta ptr4+1
; Clear TM buf while we have zero in A
ldx #.sizeof(tm)-1
: sta TM,x
dex
bpl :-
; Divide t/86400
jsr udiv32
; Store the quotient (the number of full days), and increment
; by one as epoch starts at day 1.
clc
lda ptr1
adc #1
sta TM + tm::tm_mday
lda ptr1+1
adc #0
sta TM + tm::tm_mday+1
; Now divide the number of remaining seconds by 3600,
; to get the number of hours, and the seconds in the
; current hour, in neat 16-bit integers.
; Load the previous division's remainder (in ptr2:tmp3:tmp4)
; as dividend
lda ptr2
sta ptr1
lda ptr2+1
sta ptr1+1
lda tmp3
sta sreg
; We ignore the high byte stored in tmp4 because it will be
; zero. We'll zero sreg+1 right below, when we'll have
; a convenient zero already in A.
; Load divisor
lda #<3600
sta ptr3
lda #>3600
sta ptr3+1
; Zero the two high bytes of the divisor and the high byte
; of the dividend.
.if .cpu .bitand CPU_ISET_65SC02
stz ptr4
stz ptr4+1
stz sreg+1
.else
lda #$00
sta ptr4
sta ptr4+1
sta sreg+1
.endif
; Do the division
jsr udiv32
; Store year
lda #70
sta TM + tm::tm_year
; Store hours (the quotient of the last division)
lda ptr1
sta TM + tm::tm_hour
lda ptr1+1
sta TM + tm::tm_hour+1
; Store seconds (the remainder of the last division)
lda ptr2
sta TM + tm::tm_sec
lda ptr2+1
sta TM + tm::tm_sec+1
; The rest of the struct tm fields are zero. mktime
; will take care of shifting extra seconds to minutes,
; and extra days to months and years.
; Call mktime
lda #<TM
ldx #>TM
jsr _mktime
; And return our pointer
lda #<TM
ldx #>TM
rts
.bss
TM: .tag tm

View File

@@ -1,59 +0,0 @@
/*****************************************************************************/
/* */
/* asctime.c */
/* */
/* Convert a broken down time into a string */
/* */
/* */
/* */
/* (C) 2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* 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 <stdio.h>
#include <time.h>
/*****************************************************************************/
/* Code */
/*****************************************************************************/
/*
CAUTION: we need to reserve enough space to be able to hold the maximum
length string:
1234567890123456789012345678901234567
"Wednesday September ..1 00:00:00 1970"
*/
char* __fastcall__ asctime (const struct tm* timep)
{
static char buf[38];
/* Format into given buffer and return the result */
return strftime (buf, sizeof (buf), "%c\n", timep)? buf : 0;
}

81
libsrc/common/asctime.s Normal file
View File

@@ -0,0 +1,81 @@
;
; Colin Leroy-Mira, 2024
;
; char* __fastcall__ asctime (const struct tm* timep)
;
.export _asctime
.import _strftime, pushax
.importzp ptr1
.include "time.inc"
.macpack cpu
; ------------------------------------------------------------------------
; Special values
; We need to be able to store up to 38 bytes:
; 1234567890123456789012345678901234567
; "Wednesday September ..1 00:00:00 1970"
MAX_BUF_LEN = 38
; ------------------------------------------------------------------------
; Code
_asctime:
; Backup timep
.if (.cpu .bitand ::CPU_ISET_65SC02)
pha
phx
.else
sta ptr1
stx ptr1+1
.endif
; Push buf
lda #<buf
ldx #>buf
jsr pushax
; Push sizeof(buf)
lda #<MAX_BUF_LEN
ldx #>MAX_BUF_LEN
jsr pushax
; Push format string
lda #<fmt
ldx #>fmt
jsr pushax
; Restore timep
.if (.cpu .bitand ::CPU_ISET_65SC02)
plx
pla
.else
lda ptr1
ldx ptr1+1
.endif
; Call formatter
jsr _strftime
; Check return status
bne :+
cpx #$00
bne :+
rts
: lda #<buf
ldx #>buf
rts
.data
fmt: .byte '%'
.byte 'c'
.byte $0A
.byte $00
.bss
buf: .res MAX_BUF_LEN

View File

@@ -3,7 +3,7 @@
; 2002-10-22, Greg King
;
; This signed-division function returns both the quotient and the remainder,
; in this structure:
; in this structure: (quotient in sreg, remainder in AX)
;
; typedef struct {
; int rem, quot;

View File

@@ -7,7 +7,7 @@
.export _fclose
.import _close
.import _close, ___directerrno
.importzp ptr1
.include "errno.inc"
@@ -31,10 +31,7 @@
; File is not open
lda #EINVAL
jsr ___seterrno
lda #$FF ; Return -1
tax
rts
jmp ___directerrno
; File is open. Reset the flags and close the file.
@@ -47,4 +44,3 @@
jmp _close ; Will set errno and return an error flag
.endproc

View File

@@ -1,58 +0,0 @@
/*
** fgetc.c
**
** (C) Copyright 1998, 2002 Ullrich von Bassewitz (uz@cc65.org)
**
*/
#include <stdio.h>
#include <unistd.h>
#include "_file.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
int __fastcall__ fgetc (register FILE* f)
{
unsigned char c;
/* Check if the file is open or if there is an error condition */
if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
return EOF;
}
/* If we have a pushed back character, return it */
if (f->f_flags & _FPUSHBACK) {
f->f_flags &= ~_FPUSHBACK;
return f->f_pushback;
}
/* Read one byte */
switch (read (f->f_fd, &c, 1)) {
case -1:
/* Error */
f->f_flags |= _FERROR;
return EOF;
case 0:
/* EOF */
f->f_flags |= _FEOF;
return EOF;
default:
/* Char read */
return c;
}
}

92
libsrc/common/fgetc.s Normal file
View File

@@ -0,0 +1,92 @@
;
; Colin Leroy-Mira, 2024
;
; int __fastcall__ fgetc (register FILE* f)
;
.export _fgetc
.import _read, pusha0, pushax, popptr1, incsp2, returnFFFF
.importzp ptr1
.include "stdio.inc"
.include "_file.inc"
_fgetc:
sta ptr1
stx ptr1+1
jsr pushax ; Backup our ptr
ldy #_FILE::f_flags
lda (ptr1),y
tax
and #_FOPEN ; Check for file open
beq ret_eof
txa
and #(_FERROR|_FEOF); Check for error/eof
bne ret_eof
txa
and #_FPUSHBACK ; Check for pushed back char
beq do_read
txa
and #<(~_FPUSHBACK) ; Reset flag
sta (ptr1),y
.assert _FILE::f_pushback = _FILE::f_flags+1, error
iny
jsr incsp2 ; Drop our ptr copy
lda (ptr1),y ; Return pushed back char
ldx #$00
rts
do_read:
; Push _read parameters
ldy #_FILE::f_fd
lda (ptr1),y
jsr pusha0
lda #<c
ldx #>c
jsr pushax
lda #$01
ldx #$00
; Read
jsr _read
; Check for errors
cmp #$00
beq set_feof
cmp #<(-1)
beq set_ferror
jsr incsp2
; Return char
ldx #$00
lda c
rts
ret_eof:
jsr incsp2
jmp returnFFFF
set_ferror:
lda #_FERROR
bne set_err
set_feof:
lda #_FEOF
set_err:
pha
jsr popptr1
pla
ldy #_FILE::f_flags
ora (ptr1),y
sta (ptr1),y
jmp returnFFFF
.bss
c: .res 1

View File

@@ -1,68 +0,0 @@
/*
** Ullrich von Bassewitz, 11.08.1998
**
** char* fgets (char* s, int size, FILE* f);
*/
#include <stdio.h>
#include <errno.h>
#include "_file.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
char* __fastcall__ fgets (char* s, unsigned size, register FILE* f)
{
register char* p = s;
unsigned i;
int c;
if (size == 0) {
/* Invalid size */
return (char*) _seterrno (EINVAL);
}
/* Read input */
i = 0;
while (--size) {
/* Get next character */
if ((c = fgetc (f)) == EOF) {
/* Error or EOF */
if ((f->f_flags & _FERROR) != 0 || i == 0) {
/* ERROR or EOF on first char */
*p = '\0';
return 0;
} else {
/* EOF with data already read */
break;
}
}
/* One char more */
*p = c;
++p;
++i;
/* Stop at end of line */
if ((char)c == '\n') {
break;
}
}
/* Terminate the string */
*p = '\0';
/* Done */
return s;
}

119
libsrc/common/fgets.s Normal file
View File

@@ -0,0 +1,119 @@
;
; Colin Leroy-Mira, 2024
;
; char* __fastcall__ fgets (char* s, unsigned size, register FILE* f)
;
.export _fgets
.import _fgetc, popptr1, pushptr1, popax, pushax, return0, ___errno
.importzp ptr1, ptr4
.include "errno.inc"
.include "stdio.inc"
.include "_file.inc"
.macpack cpu
terminate_ptr:
lda #$00
tax
.if (.cpu .bitand ::CPU_ISET_65SC02)
sta (ptr4)
.else
tay
sta (ptr4),y
.endif
rts
_fgets:
sta ptr1
stx ptr1+1
jsr popax
sta size
stx size+1
jsr popax
sta ptr4
stx ptr4+1
sta buf
stx buf+1
.if (.cpu .bitand ::CPU_ISET_65SC02)
stz didread
.else
lda #$00 ; We have read nothing yet
sta didread
.endif
; Check size
lda size
ora size+1
bne read_loop
lda #EINVAL
sta ___errno
jmp return0
read_loop:
lda size ; Dec size
bne :+
dec size+1
: dec size
bne :+ ; Check bound
ldx size+1
beq done
: jsr pushptr1 ; Push ptr1 for backup and load it to AX for fgetc
jsr _fgetc ; Read a char
pha
jsr popptr1 ; Get ptr1 back
pla
cpx #<EOF
beq got_eof
ldy #$01
sty didread ; We read at least one char
.if (.cpu .bitand ::CPU_ISET_65SC02)
sta (ptr4)
.else
dey
sta (ptr4),y
.endif
inc ptr4
bne :+
inc ptr4+1
: cmp #$0A ; Stop at \n
beq done
clc
bcc read_loop
got_eof:
lda didread
beq stopped_at_first_char
ldy #_FILE::f_flags
lda (ptr1),y
and #_FERROR
bne stopped_at_first_char
done:
jsr terminate_ptr
ldx #>buf
lda #<buf
rts
stopped_at_first_char:
jmp terminate_ptr
.bss
c: .res 1
buf: .res 2
size: .res 2
didread:.res 1

View File

@@ -5,7 +5,7 @@
;
.export _clearerr, _feof, _ferror, _fileno, _fflush
.import return0
.import return0, ___directerrno
.importzp ptr1
.include "_file.inc"
@@ -78,10 +78,7 @@ err: rts
; If the file is not valid, fileno must set errno and return -1
error: lda #<EBADF
jsr ___seterrno
lda #$FF
tax
rts
jmp ___directerrno
.endproc
;
@@ -89,5 +86,3 @@ error: lda #<EBADF
;
_fflush = return0

View File

@@ -1,63 +0,0 @@
/*
** gets.c
**
** Ullrich von Bassewitz, 11.08.1998
*/
#include <stdio.h>
#include "_file.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
char* __fastcall__ gets (char* s)
{
register char* p = s;
int c;
unsigned i = 0;
while (1) {
/* Get next character */
if ((c = fgetc (stdin)) == EOF) {
/* Error or EOF */
*p = '\0';
if (stdin->f_flags & _FERROR) {
/* ERROR */
return 0;
} else {
/* EOF */
if (i) {
return s;
} else {
return 0;
}
}
}
/* One char more. Newline ends the input */
if ((char) c == '\n') {
*p = '\0';
break;
} else {
*p = c;
++p;
++i;
}
}
/* Done */
return s;
}

47
libsrc/common/gets.s Normal file
View File

@@ -0,0 +1,47 @@
;
; Colin Leroy-Mira, 2024
;
; char* __fastcall__ gets (char* s)
;
.export _gets
.import _fgets, _stdin, popax, pushax
.importzp ptr4
_gets:
; Push buffer
sta ptr4
stx ptr4+1
jsr pushax
; Push size (there's no limit!)
lda #$FF
tax
jsr pushax
lda _stdin
ldx _stdin+1
jsr _fgets
; Check return value
bne :+
cpx #$00
bne :+
rts
: ; At least one byte written.
jsr pushax ; Store returned pointer
; Remove \n if there is one.
lda ptr4 ; _fgets returns with ptr4 at
bne :+ ; end of buffer
dec ptr4+1
: dec ptr4
lda (ptr4),y ; _fgets returns with Y=0
cmp #$0A
bne :+
tya
sta (ptr4),y ; Set terminator over \n
: jmp popax

View File

@@ -131,6 +131,7 @@ _malloc:
sta ptr1
bcc @L1
inc ptr1+1
beq OutOfHeapSpace ; if high byte's 0, we overflowed!
@L1: ldx ptr1+1
bne @L2
cmp #HEAP_MIN_BLOCKSIZE+1
@@ -336,4 +337,3 @@ RetUserPtr:
bcc @L9
inx
@L9: rts

View File

@@ -1,184 +0,0 @@
/*****************************************************************************/
/* */
/* mktime.c */
/* */
/* Make calendar time from broken down time and cleanup */
/* */
/* */
/* */
/* (C) 2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* 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 <limits.h>
#include <stdlib.h>
#include <time.h>
#include "_is_leap_year.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
#define JANUARY 0
#define FEBRUARY 1
#define DECEMBER 11
#define JAN_1_1970 4 /* 1/1/1970 is a thursday */
static const unsigned char MonthLength [] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static const unsigned MonthDays [] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
time_t __fastcall__ mktime (register struct tm* TM)
/* Make a time in seconds since 1/1/1970 from the broken down time in TM.
** A call to mktime does also correct the time in TM to contain correct
** values.
*/
{
register div_t D;
static int Max;
static unsigned DayCount;
/* Check if TM is valid */
if (TM == 0) {
/* Invalid data */
return (time_t) -1L;
}
/* Adjust seconds. */
D = div (TM->tm_sec, 60);
TM->tm_sec = D.rem;
/* Adjust minutes */
TM->tm_min += D.quot;
D = div (TM->tm_min, 60);
TM->tm_min = D.rem;
/* Adjust hours */
TM->tm_hour += D.quot;
D = div (TM->tm_hour, 24);
TM->tm_hour = D.rem;
/* Adjust days */
TM->tm_mday += D.quot;
/* Adjust year */
while (1) {
Max = 365UL + IsLeapYear (TM->tm_year);
if ((unsigned int)TM->tm_mday > Max) {
++TM->tm_year;
TM->tm_mday -= Max;
} else {
break;
}
}
/* Adjust month and year. This is an iterative process, since changing
** the month will change the allowed days for this month.
*/
while (1) {
/* Make sure, month is in the range 0..11 */
D = div (TM->tm_mon, 12);
TM->tm_mon = D.rem;
TM->tm_year += D.quot;
/* Now check if mday is in the correct range, if not, correct month
** and eventually year and repeat the process.
*/
if (TM->tm_mon == FEBRUARY && IsLeapYear (TM->tm_year)) {
Max = 29;
} else {
Max = MonthLength[TM->tm_mon];
}
if ((unsigned int)TM->tm_mday > Max) {
/* Must correct month and eventually, year */
if (TM->tm_mon == DECEMBER) {
TM->tm_mon = JANUARY;
++TM->tm_year;
} else {
++TM->tm_mon;
}
TM->tm_mday -= Max;
} else {
/* Done */
break;
}
}
/* Ok, all time/date fields are now correct. Calculate the days in this
** year.
*/
TM->tm_yday = MonthDays[TM->tm_mon] + TM->tm_mday - 1;
if (TM->tm_mon > FEBRUARY && IsLeapYear (TM->tm_year)) {
++TM->tm_yday;
}
/* Calculate days since 1/1/1970. In the complete epoch (1/1/1970 to
** somewhere in 2106) all years dividable by 4 are leap years(1),
** so dividing by 4 gives the days that must be added because of leap years.
** (and the last leap year before 1970 was 1968)
** (1): Exception on 2100, which is not leap, and handled just after.
*/
DayCount = ((unsigned) (TM->tm_year-70)) * 365U +
(((unsigned) (TM->tm_year-(68+1))) / 4) +
TM->tm_yday;
/* Handle the 2100 exception */
if (TM->tm_year == 200 && TM->tm_mon > FEBRUARY) {
DayCount--;
} else if (TM->tm_year > 200) {
DayCount--;
}
/* Calculate the weekday */
TM->tm_wday = (JAN_1_1970 + DayCount) % 7;
/* No (US) daylight saving (for now) */
TM->tm_isdst = 0;
/* Return seconds since 1970 */
return DayCount * 86400UL +
((unsigned) TM->tm_hour) * 3600UL +
((unsigned) TM->tm_min) * 60U +
((unsigned) TM->tm_sec) -
_tz.timezone;
}

476
libsrc/common/mktime.s Normal file
View File

@@ -0,0 +1,476 @@
;
; Colin Leroy-Mira, 2024
;
; time_t __fastcall__ mktime (register struct tm* TM)
;
; Converts a struct tm to a time_t timestamp, making sure
; day, month, year, hour, minute and seconds are in the
; correct range.
;
.export _mktime
.import __tz
.import pushax, pusha0, pusheax
.import shrax2, _div, tosumulax, tosumodax, tossubeax, tosaddeax, tosumuleax
.importzp ptr2, tmp3, sreg
.include "time.inc"
; ------------------------------------------------------------------------
; Special values
FEBRUARY = 1
MARCH = 2
JAN_1_1970 = 4
N_SEC = 60
N_MIN = 60
N_HOUR = 24
N_MON = 12
N_DAY_YEAR = 365
; ------------------------------------------------------------------------
; Helpers
; Helper to shift overflows from one field to the next
; Current field in Y, divisor in A
; Keeps remainder in current field, and adds the quotient
; to the next one
adjust_field:
pha ; Push divisor
iny ; Point to high byte of current field
lda (ptr2),y
tax
dey
sty tmp3 ; Store current field (_div will mess with
lda (ptr2),y ; tmp1 and tmp2)
jsr pushax
pla ; Load divisor
ldx #$00
jsr _div
ldy tmp3 ; Store remainder in current field
sta (ptr2),y
iny
txa
sta (ptr2),y
lda sreg ; Add quotient to next field
iny
clc
adc (ptr2),y
sta (ptr2),y
iny
lda sreg+1
adc (ptr2),y
sta (ptr2),y
rts
; Returns 1 in A if the given year is a leap year. Expects a year
; from 0 to 206, without 1900 added.
is_leap_year:
cmp #$00 ; Y 0 (1900) is not a leap year
beq not_leap
cmp #$C8 ; Y 200 (2100) is not a leap year
beq not_leap
and #$03 ; Year % 4 == 0 means leap year
bne not_leap
lda #$01 ; Return 1
rts
not_leap:
lda #$00 ; Return 0
rts
; Returns the number of days in the current month/year in A
get_days_in_month:
ldy #tm::tm_mon
lda (ptr2),y
tax
lda months_len,x
cpx #FEBRUARY
beq :+
rts
: tax
ldy #tm::tm_year ; Adjust for leap years
lda (ptr2),y
jsr is_leap_year
beq :+
inx
: txa
rts
; Add AX to counter
addaxcounter:
clc
adc Counter
sta Counter ; Store in Counter
txa
adc Counter+1
sta Counter+1
rts
; Helpers for long chain of arithmetic on day counter.
; Reload Counter and push it on the stack
load_and_push_counter:
lda Counter+3
sta sreg+1
lda Counter+2
sta sreg
lda Counter
ldx Counter+1
jsr pusheax
rts
; Store result in AX:sreg to Counter
store_counter:
sta Counter
stx Counter+1
lda sreg
sta Counter+2
lda sreg+1
sta Counter+3
rts
; ------------------------------------------------------------------------
; Code
_mktime:
sta ptr2 ; Store struct to ptr2, which arithmetic
stx ptr2+1 ; functions won't touch
; Check pointer validity
ora ptr2+1
bne :+
lda #$FF
tax
sta sreg
sta sreg+1
rts
; Adjust seconds
: ldy #tm::tm_sec
lda #N_SEC
jsr adjust_field
; Adjust minutes
ldy #tm::tm_min
lda #N_MIN
jsr adjust_field
; Adjust hours
ldy #tm::tm_hour
lda #N_HOUR
jsr adjust_field
;Shift one year as long as tm_mday is more than a year
ldy #tm::tm_year
lda (ptr2),y
dec_by_year:
jsr is_leap_year ; Compute max numbers of days in year
clc
adc #<N_DAY_YEAR ; No care about carry,
sta Max ; 365+1 doesn't overflow low byte
ldy #tm::tm_mday+1 ; Do we have more days in store?
lda (ptr2),y
cmp #>N_DAY_YEAR
beq :+ ; High byte equal, check low byte
bcs do_year_dec ; High byte greater, decrement
bcc dec_by_month ; Low byte lower, we're done
: dey
lda (ptr2),y
cmp Max
bcc dec_by_month
beq dec_by_month
do_year_dec:
; Decrement days
ldy #tm::tm_mday
lda (ptr2),y
sbc Max ; Carry already set
sta (ptr2),y
iny
lda (ptr2),y
sbc #>N_DAY_YEAR
sta (ptr2),y
; Increment year
ldy #tm::tm_year
lda (ptr2),y
clc
adc #1
sta (ptr2),y ; No carry possible here either
bcc dec_by_year ; bra, go check next year
dec_by_month:
; We're done decrementing days by full years, now do it
; month per month.
ldy #tm::tm_mon
lda #N_MON
jsr adjust_field
; Get max day for this month
jsr get_days_in_month
sta Max
; So, do we have more days than this month?
ldy #tm::tm_mday+1
lda (ptr2),y
bne do_month_dec ; High byte not zero, sure we do
dey
lda (ptr2),y
cmp Max
bcc calc_tm_yday ; No
beq calc_tm_yday
do_month_dec:
; Decrement days
ldy #tm::tm_mday
lda (ptr2),y
sec
sbc Max
sta (ptr2),y
iny
lda (ptr2),y
sbc #$00
sta (ptr2),y
; Increment month
ldy #tm::tm_mon
lda (ptr2),y
clc
adc #1
sta (ptr2),y
bne dec_by_month ; Check next month
calc_tm_yday:
; We finished decrementing tm_mday and have put it in the correct
; year/month range. Now compute the day of the year.
ldy #tm::tm_mday ; Get current day of month
lda (ptr2),y
sta Counter ; Store it in Counter
lda #$00 ; Init counter high bytes
sta Counter+1
sta Counter+2
sta Counter+3
ldy #tm::tm_mon ; Get current month
lda (ptr2),y
asl
tax
clc
lda yday_by_month,x ; Get yday for this month's start
adc Counter ; Add it to counter
sta Counter
inx
lda yday_by_month,x
adc Counter+1
sta Counter+1
ldy #tm::tm_year ; Adjust for leap years (if after feb)
lda (ptr2),y
jsr is_leap_year
beq dec_counter
ldy #tm::tm_mon ; Leap year, get current month
lda (ptr2),y
cmp #MARCH
bcs store_yday
dec_counter:
lda Counter ; Decrease counter by one (yday starts at 0),
bne :+ ; unless we're after february in a leap year
dec Counter+1
: dec Counter
store_yday:
ldy #tm::tm_yday ; Store tm_yday
lda Counter
sta (ptr2),y
iny
lda Counter+1
sta (ptr2),y
; Now calculate total day count since epoch with the formula:
; ((unsigned) (TM->tm_year-70)) * 365U + (number of days per year since 1970)
; (((unsigned) (TM->tm_year-(68+1))) / 4) + (one extra day per leap year since 1970)
; TM->tm_yday (number of days in this year)
ldy #tm::tm_year ; Get full years
lda (ptr2),y
sec
sbc #70
ldx #0
jsr pushax
lda #<N_DAY_YEAR
ldx #>N_DAY_YEAR
jsr tosumulax
jsr addaxcounter
; Add one day per leap year
ldy #tm::tm_year ; Get full years
lda (ptr2),y
sec
sbc #69
ldx #0
jsr shrax2 ; Divide by 4
jsr addaxcounter
; Handle the 2100 exception (which was considered leap by "Add one day
; per leap year" just before)
ldy #tm::tm_year ; Get full years
lda (ptr2),y
cmp #201
bcc finish_calc ; <= 200, nothing to do
lda Counter
bne :+
dec Counter+1
: dec Counter
finish_calc:
; Now we can compute the weekday.
lda Counter
clc
adc #JAN_1_1970
pha
lda Counter+1
adc #0
tax
pla
jsr pushax
lda #7 ; Modulo 7
ldx #0
jsr tosumodax
ldy #tm::tm_wday ; Store tm_wday
sta (ptr2),y
iny
txa
sta (ptr2),y
; DST
lda #$00 ; Store tm_isdst
ldy #tm::tm_isdst
sta (ptr2),y
iny
sta (ptr2),y
; Our struct tm is all fixed and every field calculated.
; We can finally count seconds according to this formula:
; seconds = (full days since epoch) * 86400UL +
; ((unsigned) TM->tm_hour) * 3600UL +
; ((unsigned) TM->tm_min) * 60U +
; ((unsigned) TM->tm_sec) -
; _tz.timezone;
; We already have the number of days since epoch in our counter,
; from just before when we computed tm_wday. Reuse it.
jsr load_and_push_counter
lda #$00 ; Multiply by 86400
sta sreg+1
lda #$01
sta sreg
lda #$80
ldx #$51
jsr tosumuleax
jsr store_counter ; Store into counter
; Push counter to add 3600 * hours to it
jsr load_and_push_counter
ldx #$00 ; Load hours
stx sreg
stx sreg+1
ldy #tm::tm_hour
lda (ptr2),y
jsr pusheax ; Push
ldx #$00 ; Load 3600
stx sreg
stx sreg+1
lda #<3600
ldx #>3600
jsr tosumuleax ; Multiply (pops the pushed hours)
jsr tosaddeax ; Add to counter (pops the pushed counter)
jsr store_counter ; Store counter
; Push counter to add 60 * min to it
jsr load_and_push_counter
ldy #tm::tm_min ; Load minutes
lda (ptr2),y
jsr pusha0 ; Push
lda #N_MIN
ldx #0
stx sreg
stx sreg+1
jsr tosumulax ; Multiply
jsr tosaddeax ; Add to pushed counter
jsr store_counter ; Store
; Add seconds
jsr load_and_push_counter
ldy #tm::tm_sec ; Load seconds
lda (ptr2),y
ldx #0
stx sreg
stx sreg+1
jsr tosaddeax ; Simple addition there
; No need to store/load/push the counter here, simply to push it
; for the last substraction
jsr pusheax
; Substract timezone
lda __tz+1+3
sta sreg+1
lda __tz+1+2
sta sreg
ldx __tz+1+1
lda __tz+1
jsr tossubeax
; And we're done!
rts
.data
months_len:
.byte 31
.byte 28
.byte 31
.byte 30
.byte 31
.byte 30
.byte 31
.byte 31
.byte 30
.byte 31
.byte 30
.byte 31
yday_by_month:
.word 0
.word 31
.word 59
.word 90
.word 120
.word 151
.word 181
.word 212
.word 243
.word 273
.word 304
.word 334
.bss
Max: .res 1 ; We won't need a high byte
Counter:
.res 4

View File

@@ -50,7 +50,6 @@
*/
int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
/* Allocate a block of memory with the given "size", which is aligned to a
** memory address that is a multiple of "alignment". "alignment" MUST NOT be
@@ -64,20 +63,27 @@ int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
size_t rawsize;
size_t uppersize;
size_t lowersize;
char err;
register struct usedblock* b; /* points to raw Block */
register struct usedblock* u; /* points to User block */
register struct usedblock* p; /* Points to upper block */
/* Handle requests for zero-sized blocks */
if (size == 0) {
err_einval:
err = EINVAL;
err_out:
*memptr = NULL;
return EINVAL;
return err;
}
/* Test alignment: is it a power of two? There must be only one bit set. */
if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
*memptr = NULL;
return EINVAL;
/* Test alignment: is it a power of two? There must be one and only one bit set. */
if (alignment == 0) {
goto err_einval;
}
if (alignment & (alignment - 1)) {
goto err_einval;
}
/* Augment the block size up to the alignment, and allocate memory.
@@ -90,8 +96,8 @@ int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
/* Handle out-of-memory */
if (b == NULL) {
*memptr = NULL;
return ENOMEM;
err = ENOMEM;
goto err_out;
}
/* Create (and return) a new pointer that points to the user-visible

View File

@@ -10,7 +10,7 @@
.import _malloc, _free
.import searchenv, copyenvptr
.import __environ, __envcount, __envsize
.import return0
.import return0, ___directerrno
.import ptr1:zp, ptr2:zp, ptr3:zp, tmp1:zp
.include "errno.inc"
@@ -169,10 +169,7 @@ addentry:
; Error entries
nomem: lda #ENOMEM
error: jsr ___seterrno
lda #$FF ; Return -1
tax
rts
error: jmp ___directerrno
.endproc
@@ -184,5 +181,3 @@ error: jsr ___seterrno
name: .addr 0 ; Pointer to name
newsize: .byte 0 ; New environment size

View File

@@ -1,112 +0,0 @@
/*****************************************************************************/
/* */
/* realloc.c */
/* */
/* Change the size of an allocated memory block */
/* */
/* */
/* */
/* (C) 1998-2004 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* 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 <stdlib.h>
#include <string.h>
#include <_heap.h>
void* __fastcall__ realloc (void* block, register size_t size)
{
register struct usedblock* b;
struct usedblock* newblock;
unsigned oldsize;
unsigned newhptr;
/* Check the block parameter */
if (!block) {
/* Block is NULL, same as malloc */
return malloc (size);
}
/* Check the size parameter */
if (size == 0) {
/* Block is not NULL, but size is: free the block */
free (block);
return 0;
}
/* Make the internal used size from the given size */
size += HEAP_ADMIN_SPACE;
if (size < sizeof (struct freeblock)) {
size = sizeof (struct freeblock);
}
/* The word below the user block contains a pointer to the start of the
** raw memory block. The first word of this raw memory block is the full
** size of the block. Get a pointer to the real block, get the old block
** size.
*/
b = (((struct usedblock*) block) - 1)->start;
oldsize = b->size;
/* Is the block at the current heap top? */
if (((unsigned) b) + oldsize == ((unsigned) __heapptr)) {
/* Check if we've enough memory at the heap top */
newhptr = ((unsigned) __heapptr) - oldsize + size;
if (newhptr <= ((unsigned) __heapend)) {
/* Ok, there's space enough */
__heapptr = (unsigned*) newhptr;
b->size = size;
b->start = b;
return block;
}
}
/* The given block was not located on top of the heap, or there's no
** room left. Try to allocate a new block and copy the data.
*/
if (newblock = malloc (size)) {
/* Adjust the old size to the user visible portion */
oldsize -= HEAP_ADMIN_SPACE;
/* If the new block is larger than the old one, copy the old
** data only
*/
if (size > oldsize) {
size = oldsize;
}
/* Copy the block data */
memcpy (newblock, block, size);
free (block);
}
return newblock;
}

213
libsrc/common/realloc.s Normal file
View File

@@ -0,0 +1,213 @@
;
; Colin Leroy-Mira, 2024
;
; void* __fastcall__ realloc (void* block, register size_t size)
;
.importzp ptr1, ptr2, ptr3, ptr4, tmp1, tmp2, tmp3, tmp4, sp
.import _malloc, _memcpy, _free
.import pushax, popptr1, return0
.import incsp2, decsp2
.export _realloc
.include "_heap.inc"
.macpack generic
;----------------------------------------------------------------------------
; Aliases for clarity
block = ptr1
size = ptr2
ublock = ptr3
oldsize = ptr4
newblock = tmp1 ; (and tmp2)
orgblock = tmp3 ; (and tmp4)
;----------------------------------------------------------------------------
; Code
_realloc:
sta size ; Store size
stx size+1
jsr popptr1 ; Pop block
lda block+1 ; Is block null?
tax
ora block
bne :+
lda size ; Block is null, just malloc
ldx size+1
jmp _malloc
: lda size ; Is size 0?
ora size+1
bne :+
lda block ; It is: free block (high byte already in X)
jsr _free
jmp return0
: clc ; Add internal used size
lda size
adc #HEAP_ADMIN_SPACE
sta size
bcc :+
inc size+1
bne :+
lda #$00 ; Size high byte now 0: We overflowed!
tax
rts
: ldx size+1 ; Should we round size up?
bne :+
cmp #.sizeof (freeblock)
bcs :+
lda #.sizeof (freeblock)
sta size ; (we presuppose that sizeof (freeblock) is < 256)
: lda block ; Get pointer to raw memory block
sta orgblock ; Store original pointer
sec
sbc #.sizeof(usedblock)
sta ublock
lda block+1
sta orgblock+1 ; Finish storing original pointer
sbc #0
sta ublock+1 ; We have our usedblock struct
; Get block start
ldy #usedblock::start+1
lda (ublock),y
tax ; Backup ublock high
dey
lda (ublock),y
sta ublock ; Store ublock
stx ublock+1
; Remember oldsize
ldy #usedblock::size+1
lda (ublock),y
sta oldsize+1
dey
lda (ublock),y
sta oldsize
clc ; Is the block at heap top?
adc ublock
tay
lda ublock+1
adc oldsize+1
cmp ___heapptr+1
bne must_malloc_new
cpy ___heapptr
bne must_malloc_new
tya ; Put ___heapptr back in A
sec ; Check if we have enough memory at heap top
sbc oldsize ; Substract oldsize
sta newblock
lda ___heapptr+1
sbc oldsize+1
sta newblock+1
clc
lda newblock ; And add size
adc size
sta newblock
lda newblock+1
adc size+1
sta newblock+1
bcs must_malloc_new ; If we have a carry there we overflowed
cmp ___heapend+1
bne :+
lda newblock
cmp ___heapend
: bcc :+
bne must_malloc_new
: lda newblock ; There is enough space
sta ___heapptr ; Update heapptr
lda newblock+1
sta ___heapptr+1
ldy #usedblock::start+1
lda ublock+1
sta (ublock),y ; Update block start
dey
lda ublock
sta (ublock),y
dey
.assert usedblock::size = usedblock::start-2, error
lda size+1
sta (ublock),y ; Update block size
dey
lda size
sta (ublock),y
lda orgblock ; Return original block
ldx orgblock+1
rts
must_malloc_new: ; The block is not at heap top, or too big
lda size+1
pha ; Backup new size (at this point the only ptr
tax ; we'll need after malloc). tmp* are safe
lda size ; from malloc, memcpy and free.
pha
jsr _malloc
cmp #$00 ; Did malloc succeed?
bne :+
cpx #$00
bne :+
pla ; Pop size backup and return NULL
pla
txa ; X already 0
rts ; No
: sta newblock ; Yes, store newblock
stx newblock+1
jsr pushax ; Push newblock for memcpy
lda orgblock ; Push orgblock for memcpy
ldx orgblock+1
jsr pushax
sec ; Remove admin space from oldsize
lda oldsize
sbc #<HEAP_ADMIN_SPACE
sta oldsize
lda oldsize+1
sbc #>HEAP_ADMIN_SPACE
sta oldsize+1
pla ; Restore new size to AX
tay
pla
tax
tya
cmp oldsize ; Find the smallest size
bcc :+
cpx oldsize+1
bcc :+
lda oldsize
ldx oldsize+1
: jsr _memcpy ; And copy data
lda orgblock ; Free old block
ldx orgblock+1
jsr _free
lda newblock ; Return new block
ldx newblock+1
rts

View File

@@ -62,10 +62,6 @@
; File is not open or the character is invalid
error: lda #EINVAL
jsr ___seterrno
lda #$FF ; Return -1
tax
rts
jmp ___directerrno
.endproc

View File

@@ -6,7 +6,7 @@
; void BitOtherClip (void *proc1, void* proc2, char skipl, char skipr, int skipy,
; struct iconpic *myGfx);
; both proc1, proc2 should be: char __fastcall something (void);
; both proc1, proc2 should be: char foo (void);
; proc1 is called before reading a byte (.A returns next data)
; proc2 is called before reading each byte which is not pattern (code >219)

View File

@@ -18,7 +18,7 @@
.import ldeaxysp, decsp2, pushax, incsp8
.import tosandeax,decax1,tosdiveax,axlong,ldaxysp
.import lynxskip0, lynxblock,tosasreax
.import __BLOCKSIZE__
.import __BANK0BLOCKSIZE__
.importzp _FileCurrBlock
.segment "CODE"
@@ -32,15 +32,15 @@
jsr ldeaxysp
jsr pusheax
ldx #$00
lda #<(__BLOCKSIZE__/1024 + 9)
lda #<(__BANK0BLOCKSIZE__/1024 + 9)
jsr tosasreax
sta _FileCurrBlock
jsr lynxblock
ldy #$05
jsr ldeaxysp
jsr pusheax
lda #<(__BLOCKSIZE__-1)
ldx #>(__BLOCKSIZE__-1)
lda #<(__BANK0BLOCKSIZE__-1)
ldx #>(__BANK0BLOCKSIZE__-1)
jsr axlong
jsr tosandeax
eor #$FF

View File

@@ -17,7 +17,7 @@
.include "extzp.inc"
.export lynxskip0, lynxread0
.export lynxblock
.import __BLOCKSIZE__
.import __BANK0BLOCKSIZE__
.code
@@ -88,7 +88,7 @@ lynxblock:
lda __iodat
sta IODAT
stz _FileBlockByte
lda #<($100-(>__BLOCKSIZE__))
lda #<($100-(>__BANK0BLOCKSIZE__))
sta _FileBlockByte+1
ply
plx

View File

@@ -33,7 +33,7 @@ loop1:
cont1:
jsr read_byte
sta (load_ptr2),y
sta PALETTE ; feedback ;-)
sta PALETTE + 1 ; feedback ;-)
iny
bne loop1
inc load_ptr2+1
@@ -69,6 +69,8 @@ again:
; last action : clear interrupt
;
exit:
lda #$10
sta INTRST
clc
rts

View File

@@ -8,12 +8,18 @@
.import incsp2
.importzp sp, ptr1
.macpack cpu
.proc popptr1 ; 14 bytes (four usages = at least 2 bytes saved)
ldy #1
lda (sp),y ; get hi byte
sta ptr1+1 ; into ptr hi
dey ; no optimization for 65C02 here to have Y=0 at exit!
dey ; dey even for for 65C02 here to have Y=0 at exit!
.if (.cpu .bitand ::CPU_ISET_65SC02)
lda (sp) ; get lo byte
.else
lda (sp),y ; get lo byte
.endif
sta ptr1 ; to ptr lo
jmp incsp2
.endproc

View File

@@ -7,6 +7,8 @@
.export push0, pusha0, pushax
.importzp sp
.macpack cpu
push0: lda #0
pusha0: ldx #0
@@ -29,7 +31,11 @@ pusha0: ldx #0
sta (sp),y ; (27)
pla ; (31)
dey ; (33)
.if (.cpu .bitand ::CPU_ISET_65SC02)
sta (sp) ; (37)
.else
sta (sp),y ; (38)
rts ; (44)
.endif
rts ; (44/43)
.endproc

14
libsrc/runtime/pushptr1.s Normal file
View File

@@ -0,0 +1,14 @@
;
; Colin Leroy-Mira, 2024
;
; CC65 runtime: Push ptr1 to stack.
; A/X destroyed (set to ptr1)
.export pushptr1
.import pushax
.importzp ptr1
pushptr1:
lda ptr1
ldx ptr1+1
jmp pushax

View File

@@ -0,0 +1,15 @@
;
; Ullrich von Bassewitz, 25.10.2000
;
; CC65 runtime: Return -1 in a/x
;
.export returnFFFF
.proc returnFFFF
lda #$FF
tax
rts
.endproc

View File

@@ -8,10 +8,15 @@
;
.export exit, args, _open, _close, _read, _write
.export __sysremove, ___osmaperrno
__sysremove := $FFF2
___osmaperrno := $FFF3
_open := $FFF4
_close := $FFF5
_read := $FFF6
_write := $FFF7
args := $FFF8
exit := $FFF9
; $FFFA-FFFF are hardware vectors, extend before not after!