Merge branch 'cc65:master' into master
This commit is contained in:
20
libsrc/apple2/beep.s
Normal file
20
libsrc/apple2/beep.s
Normal 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
20
libsrc/apple2/bell.s
Normal 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
|
||||
@@ -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
|
||||
|
||||
17
libsrc/apple2/detect_iigs.s
Normal file
17
libsrc/apple2/detect_iigs.s
Normal 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
|
||||
22
libsrc/apple2/get_iigs_speed.s
Normal file
22
libsrc/apple2/get_iigs_speed.s
Normal 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
|
||||
@@ -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
|
||||
|
||||
29
libsrc/apple2/set_iigs_speed.s
Normal file
29
libsrc/apple2/set_iigs_speed.s
Normal 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
54
libsrc/apple2/sleep.s
Normal 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
|
||||
@@ -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
20
libsrc/apple2/wait.s
Normal 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
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
129
libsrc/common/_time_t_to_tm.s
Normal file
129
libsrc/common/_time_t_to_tm.s
Normal 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
|
||||
@@ -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
81
libsrc/common/asctime.s
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
92
libsrc/common/fgetc.s
Normal 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
|
||||
@@ -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
119
libsrc/common/fgets.s
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
47
libsrc/common/gets.s
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
476
libsrc/common/mktime.s
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
213
libsrc/common/realloc.s
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
14
libsrc/runtime/pushptr1.s
Normal 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
|
||||
15
libsrc/runtime/returnFFFF.s
Normal file
15
libsrc/runtime/returnFFFF.s
Normal 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
|
||||
@@ -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!
|
||||
|
||||
Reference in New Issue
Block a user