add rp6502 target

This commit is contained in:
rumbledethumps 2023-11-16 18:46:16 -08:00
parent d7d1d89698
commit b17c4d3434
37 changed files with 1253 additions and 0 deletions

101
asminc/rp6502.inc Normal file
View File

@ -0,0 +1,101 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
; RIA UART
RIA_READY := $FFE0 ; TX=$80 RX=$40
RIA_TX := $FFE1
RIA_RX := $FFE2
; VSYNC from PIX VGA
RIA_VSYNC := $FFE3
; RIA XRAM portal 0
RIA_RW0 := $FFE4
RIA_STEP0 := $FFE5
RIA_ADDR0 := $FFE6
; RIA XRAM portal 1
RIA_RW1 := $FFE8
RIA_STEP1 := $FFE9
RIA_ADDR1 := $FFEA
; RIA OS fastcall
RIA_XSTACK := $FFEC
RIA_ERRNO := $FFED
RIA_OP := $FFEF
RIA_IRQ := $FFF0
RIA_SPIN := $FFF1
RIA_BUSY := $FFF2 ; Bit $80
RIA_A := $FFF4
RIA_X := $FFF6
RIA_SREG := $FFF8
; RIA OS operation numbers
RIA_OP_EXIT := $FF
RIA_OP_ZXSTACK := $00
RIA_OP_XREG := $01
RIA_OP_PHI2 := $02
RIA_OP_CODEPAGE := $03
RIA_OP_LRAND := $04
RIA_OP_STDIN_OPT := $05
RIA_OP_CLOCK_GETRES := $10
RIA_OP_CLOCK_GETTIME := $11
RIA_OP_CLOCK_SETTIME := $12
RIA_OP_CLOCK_GETTIMEZONE := $13
RIA_OP_OPEN := $14
RIA_OP_CLOSE := $15
RIA_OP_READ_XSTACK := $16
RIA_OP_READ_XRAM := $17
RIA_OP_WRITE_XSTACK := $18
RIA_OP_WRITE_XRAM := $19
RIA_OP_LSEEK := $1A
RIA_OP_UNLINK := $1B
RIA_OP_RENAME := $1C
; 6522 VIA
VIA := $FFD0 ; VIA base address
VIA_PB := VIA+$0 ; Port register B
VIA_PA1 := VIA+$1 ; Port register A
VIA_PRB := VIA+$0 ; *** Deprecated ***
VIA_PRA := VIA+$1 ; *** Deprecated ***
VIA_DDRB := VIA+$2 ; Data direction register B
VIA_DDRA := VIA+$3 ; Data direction register A
VIA_T1CL := VIA+$4 ; Timer 1, low byte
VIA_T1CH := VIA+$5 ; Timer 1, high byte
VIA_T1LL := VIA+$6 ; Timer 1 latch, low byte
VIA_T1LH := VIA+$7 ; Timer 1 latch, high byte
VIA_T2CL := VIA+$8 ; Timer 2, low byte
VIA_T2CH := VIA+$9 ; Timer 2, high byte
VIA_SR := VIA+$A ; Shift register
VIA_CR := VIA+$B ; Auxiliary control register
VIA_PCR := VIA+$C ; Peripheral control register
VIA_IFR := VIA+$D ; Interrupt flag register
VIA_IER := VIA+$E ; Interrupt enable register
VIA_PA2 := VIA+$F ; Port register A w/o handshake
; Values in ___oserror are the union of these FatFs errors and errno.inc
.enum
FR_OK = 32 ; Succeeded
FR_DISK_ERR ; A hard error occurred in the low level disk I/O layer
FR_INT_ERR ; Assertion failed
FR_NOT_READY ; The physical drive cannot work
FR_NO_FILE ; Could not find the file
FR_NO_PATH ; Could not find the path
FR_INVALID_NAME ; The path name format is invalid
FR_DENIED ; Access denied due to prohibited access or directory full
FR_EXIST ; Access denied due to prohibited access
FR_INVALID_OBJECT ; The file/directory object is invalid
FR_WRITE_PROTECTED ; The physical drive is write protected
FR_INVALID_DRIVE ; The logical drive number is invalid
FR_NOT_ENABLED ; The volume has no work area
FR_NO_FILESYSTEM ; There is no valid FAT volume
FR_MKFS_ABORTED ; The f_mkfs() aborted due to any problem
FR_TIMEOUT ; Could not get a grant to access the volume within defined period
FR_LOCKED ; The operation is rejected according to the file sharing policy
FR_NOT_ENOUGH_CORE ; LFN working buffer could not be allocated
FR_TOO_MANY_OPEN_FILES ; Number of open files > FF_FS_LOCK
FR_INVALID_PARAMETER ; Given parameter is invalid
.endenum

42
cfg/rp6502.cfg Normal file
View File

@ -0,0 +1,42 @@
#
# Copyright (c) 2023 Rumbledethumps
#
# SPDX-License-Identifier: Zlib
# SPDX-License-Identifier: BSD-3-Clause
# SPDX-License-Identifier: Unlicense
#
SYMBOLS {
__STARTUP__: type = import;
__STACKSIZE__: type = weak, value = $0800;
}
MEMORY {
ZP: file = "", define = yes, start = $0000, size = $0100;
CPUSTACK: file = "", start = $0100, size = $0100;
RAM: file = %O, define = yes, start = $0200, size = $FD00 - __STACKSIZE__;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
STARTUP: load = RAM, type = ro;
LOWCODE: load = RAM, type = ro, optional = yes;
ONCE: load = RAM, type = ro, optional = yes;
CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw, define = yes;
BSS: load = RAM, type = bss, define = yes;
}
FEATURES {
CONDES: type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__,
segment = ONCE;
CONDES: type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__,
segment = RODATA;
CONDES: type = interruptor,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__,
segment = RODATA,
import = __CALLIRQ__;
}

246
include/rp6502.h Normal file
View File

@ -0,0 +1,246 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#ifndef _RP6502_H
#define _RP6502_H
/* RP6502 VIA $FFD0-$FFDF */
#include <_6522.h>
#define VIA (*(volatile struct __6522 *)0xFFD0)
/* RP6502 RIA $FFE0-$FFF9 */
struct __RP6502
{
const unsigned char ready;
unsigned char tx;
const unsigned char rx;
const unsigned char vsync;
unsigned char rw0;
unsigned char step0;
unsigned int addr0;
unsigned char rw1;
unsigned char step1;
unsigned int addr1;
unsigned char xstack;
unsigned char errno_lo;
unsigned char errno_hi;
unsigned char op;
unsigned char irq;
const unsigned char spin;
const unsigned char busy;
const unsigned char lda;
unsigned char a;
const unsigned char ldx;
unsigned char x;
const unsigned char rts;
unsigned int sreg;
};
#define RIA (*(volatile struct __RP6502 *)0xFFE0)
#define RIA_READY_TX_BIT 0x80
#define RIA_READY_RX_BIT 0x40
#define RIA_BUSY_BIT 0x80
/* XSTACK helpers */
void __fastcall__ ria_push_long(unsigned long val);
void __fastcall__ ria_push_int(unsigned int val);
#define ria_push_char(v) RIA.xstack = v
long __fastcall__ ria_pop_long(void);
int __fastcall__ ria_pop_int(void);
#define ria_pop_char() RIA.xstack
/* Set the RIA fastcall register */
void __fastcall__ ria_set_axsreg(unsigned long axsreg);
void __fastcall__ ria_set_ax(unsigned int ax);
#define ria_set_a(v) RIA.a = v
/* Run an OS operation */
int __fastcall__ ria_call_int(unsigned char op);
long __fastcall__ ria_call_long(unsigned char op);
/* These run _mappederrno() on error */
int __fastcall__ ria_call_int_errno(unsigned char op);
long __fastcall__ ria_call_long_errno(unsigned char op);
/* OS operation numbers */
#define RIA_OP_EXIT 0xFF
#define RIA_OP_ZXSTACK 0x00
#define RIA_OP_XREG 0x01
#define RIA_OP_PHI2 0x02
#define RIA_OP_CODEPAGE 0x03
#define RIA_OP_LRAND 0x04
#define RIA_OP_STDIN_OPT 0x05
#define RIA_OP_CLOCK_GETRES 0x10
#define RIA_OP_CLOCK_GETTIME 0x11
#define RIA_OP_CLOCK_SETTIME 0x12
#define RIA_OP_CLOCK_GETTIMEZONE 0x13
#define RIA_OP_OPEN 0x14
#define RIA_OP_CLOSE 0x15
#define RIA_OP_READ_XSTACK 0x16
#define RIA_OP_READ_XRAM 0x17
#define RIA_OP_WRITE_XSTACK 0x18
#define RIA_OP_WRITE_XRAM 0x19
#define RIA_OP_LSEEK 0x1A
#define RIA_OP_UNLINK 0x1B
#define RIA_OP_RENAME 0x1C
/* C API for the operating system. */
int __cdecl__ xreg(char device, char channel, unsigned char address, ...);
int __fastcall__ phi2(void);
int __fastcall__ codepage(void);
long __fastcall__ lrand(void);
int __fastcall__ stdin_opt(unsigned long ctrl_bits, unsigned char str_length);
int __fastcall__ read_xstack(void *buf, unsigned count, int fildes);
int __fastcall__ read_xram(unsigned buf, unsigned count, int fildes);
int __fastcall__ write_xstack(const void *buf, unsigned count, int fildes);
int __fastcall__ write_xram(unsigned buf, unsigned count, int fildes);
/* XREG location helpers */
#define xreg_ria_keyboard(...) xreg(0, 0, 0, __VA_ARGS__)
#define xreg_ria_mouse(...) xreg(0, 0, 1, __VA_ARGS__)
#define xreg_vga_canvas(...) xreg(1, 0, 0, __VA_ARGS__)
#define xreg_vga_mode(...) xreg(1, 0, 1, __VA_ARGS__)
/* XRAM structure helpers */
#define xram0_struct_set(addr, type, member, val) \
RIA.addr0 = (unsigned)(&((type *)0)->member) + (unsigned)addr; \
switch (sizeof(((type *)0)->member)) \
{ \
case 1: \
RIA.rw0 = val; \
break; \
case 2: \
RIA.step0 = 1; \
RIA.rw0 = val & 0xff; \
RIA.rw0 = (val >> 8) & 0xff; \
break; \
case 4: \
RIA.step0 = 1; \
RIA.rw0 = (unsigned long)val & 0xff; \
RIA.rw0 = ((unsigned long)val >> 8) & 0xff; \
RIA.rw0 = ((unsigned long)val >> 16) & 0xff; \
RIA.rw0 = ((unsigned long)val >> 24) & 0xff; \
break; \
}
#define xram1_struct_set(addr, type, member, val) \
RIA.addr1 = (unsigned)(&((type *)0)->member) + (unsigned)addr; \
switch (sizeof(((type *)0)->member)) \
{ \
case 1: \
RIA.rw1 = val; \
break; \
case 2: \
RIA.step1 = 1; \
RIA.rw1 = val & 0xff; \
RIA.rw1 = (val >> 8) & 0xff; \
break; \
case 4: \
RIA.step1 = 1; \
RIA.rw1 = (unsigned long)val & 0xff; \
RIA.rw1 = ((unsigned long)val >> 8) & 0xff; \
RIA.rw1 = ((unsigned long)val >> 16) & 0xff; \
RIA.rw1 = ((unsigned long)val >> 24) & 0xff; \
break; \
}
typedef struct
{
unsigned char x_wrap; // bool
unsigned char y_wrap; // bool
int x_pos_px;
int y_pos_px;
int width_chars;
int height_chars;
unsigned xram_data_ptr;
unsigned xram_palette_ptr;
unsigned xram_font_ptr;
} vga_mode1_config_t;
typedef struct
{
unsigned char x_wrap; // bool
unsigned char y_wrap; // bool
int x_pos_px;
int y_pos_px;
int width_tiles;
int height_tiles;
unsigned xram_data_ptr;
unsigned xram_palette_ptr;
unsigned xram_tile_ptr;
} vga_mode2_config_t;
typedef struct
{
unsigned char x_wrap; // bool
unsigned char y_wrap; // bool
int x_pos_px;
int y_pos_px;
int width_px;
int height_px;
unsigned xram_data_ptr;
unsigned xram_palette_ptr;
} vga_mode3_config_t;
typedef struct
{
int x_pos_px;
int y_pos_px;
unsigned xram_sprite_ptr;
unsigned char log_size;
unsigned char has_opacity_metadata; // bool
} vga_mode4_sprite_t;
typedef struct
{
int transform[6];
int x_pos_px;
int y_pos_px;
unsigned xram_sprite_ptr;
unsigned char log_size;
unsigned char has_opacity_metadata; // bool
} vga_mode4_asprite_t;
/* Values in __oserror are the union of these FatFs errors and errno.h */
typedef enum
{
FR_OK = 32, /* Succeeded */
FR_DISK_ERR, /* A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* Assertion failed */
FR_NOT_READY, /* The physical drive cannot work */
FR_NO_FILE, /* Could not find the file */
FR_NO_PATH, /* Could not find the path */
FR_INVALID_NAME, /* The path name format is invalid */
FR_DENIED, /* Access denied due to prohibited access or directory full */
FR_EXIST, /* Access denied due to prohibited access */
FR_INVALID_OBJECT, /* The file/directory object is invalid */
FR_WRITE_PROTECTED, /* The physical drive is write protected */
FR_INVALID_DRIVE, /* The logical drive number is invalid */
FR_NOT_ENABLED, /* The volume has no work area */
FR_NO_FILESYSTEM, /* There is no valid FAT volume */
FR_MKFS_ABORTED, /* The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* Could not get a grant to access the volume within defined period */
FR_LOCKED, /* The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER /* Given parameter is invalid */
} FRESULT;
#endif /* _RP6502_H */

View File

@ -33,6 +33,7 @@ TARGETS = apple2 \
none \
osic1p \
pce \
rp6502 \
sim6502 \
sim65c02 \
supervision \

16
libsrc/rp6502/close.c Normal file
View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <errno.h>
int __fastcall__ close(int fd)
{
ria_set_ax(fd);
return ria_call_int_errno(RIA_OP_CLOSE);
}

14
libsrc/rp6502/codepage.c Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ codepage(void)
{
return ria_call_int(RIA_OP_CODEPAGE);
}

54
libsrc/rp6502/crt0.s Normal file
View File

@ -0,0 +1,54 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
; Boilerplate crt0.s
.export _init, _exit
.import _main
.export __STARTUP__ : absolute = 1
.import __RAM_START__, __RAM_SIZE__
.import copydata, zerobss, initlib, donelib
.include "rp6502.inc"
.include "zeropage.inc"
.segment "STARTUP"
; Essential 6502 startup the CPU doesn't do
_init:
ldx #$FF
txs
cld
; Set cc65 argument stack pointer
lda #<(__RAM_START__ + __RAM_SIZE__)
sta sp
lda #>(__RAM_START__ + __RAM_SIZE__)
sta sp+1
; Initialize memory storage
jsr zerobss ; Clear BSS segment
jsr copydata ; Initialize DATA segment
jsr initlib ; Run constructors
; Call main()
jsr _main
; Back from main() also the _exit entry
; Stack the exit value in case destructors call OS
_exit:
phx
pha
jsr donelib ; Run destructors
pla
sta RIA_A
plx
stx RIA_X
lda #$FF ; exit()
sta RIA_OP
stp

18
libsrc/rp6502/getres.c Normal file
View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <time.h>
extern int __clock_gettimespec(struct timespec *ts, unsigned char op);
int clock_getres(clockid_t clock_id, struct timespec *res)
{
ria_set_ax(clock_id);
return __clock_gettimespec(res, RIA_OP_CLOCK_GETRES);
}

20
libsrc/rp6502/gettime.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <time.h>
extern int __clock_gettimespec(struct timespec *ts, unsigned char op);
int clock_gettime(clockid_t clock_id, struct timespec *tp)
{
(void)clock_id;
/* time.s doesn't set the stack value for clock_id (bug?) */
ria_set_ax(CLOCK_REALTIME);
return __clock_gettimespec(tp, RIA_OP_CLOCK_GETTIME);
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <time.h>
int __clock_gettimespec(struct timespec *ts, unsigned char op)
/* Internal method shared by clock_getres and clock_gettime. */
{
int ax = ria_call_int_errno(op);
if (ax >= 0)
{
ts->tv_sec = ria_pop_long();
ts->tv_nsec = ria_pop_long();
}
return ax;
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <time.h>
int clock_gettimezone(clockid_t clock_id, struct _timezone *tz)
{
int ax;
ria_set_ax(clock_id);
ax = ria_call_int_errno(RIA_OP_CLOCK_GETTIMEZONE);
if (ax >= 0)
{
char i;
for (i = 0; i < sizeof(struct _timezone); i++)
((char *)tz)[i] = ria_pop_char();
}
return ax;
}

16
libsrc/rp6502/initenv.s Normal file
View File

@ -0,0 +1,16 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
.constructor initenv, 24
.import __environ, __envcount, __envsize
.segment "ONCE"
.proc initenv
rts
.endproc

51
libsrc/rp6502/irq.s Normal file
View File

@ -0,0 +1,51 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
.export initirq, doneirq
.import callirq, _exit
.include "rp6502.inc"
.segment "ONCE"
initirq:
lda #<handler
ldx #>handler
sei
sta $FFFE
stx $FFFF
cli
rts
.code
doneirq:
sei
rts
.segment "LOWCODE"
handler:
cld
phx
tsx
pha
inx
inx
lda $100,X
and #$10
bne break
phy
jsr callirq
ply
pla
plx
rti
break:
lda #$FF
sta RIA_A
jmp _exit

14
libsrc/rp6502/lrand.c Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
long __fastcall__ lrand(void)
{
return ria_call_long(RIA_OP_LRAND);
}

19
libsrc/rp6502/lseek.c Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <unistd.h>
off_t __fastcall__ lseek(int fd, off_t offset, int whence)
{
/* Modified argument order for short stacking offset */
ria_push_long(offset);
ria_push_char(whence);
ria_set_ax(fd);
return ria_call_long_errno(RIA_OP_LSEEK);
}

16
libsrc/rp6502/mainargs.s Normal file
View File

@ -0,0 +1,16 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
.constructor initmainargs, 24
.import __argc, __argv
.segment "ONCE"
.proc initmainargs
rts
.endproc

26
libsrc/rp6502/open.c Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <errno.h>
#include <string.h>
int __cdecl__ open(const char *name, int flags, ...)
{
size_t namelen = strlen(name);
if (namelen > 255)
{
return _mappederrno(EINVAL);
}
while (namelen)
{
ria_push_char(name[--namelen]);
}
ria_set_ax(flags);
return ria_call_int_errno(RIA_OP_OPEN);
}

86
libsrc/rp6502/oserrlist.s Normal file
View File

@ -0,0 +1,86 @@
;
; 2002-07-18, Ullrich von Bassewitz
; 2022, ChaN
; 2023, Rumbledethumps
;
; Defines the platform-specific error list.
;
; The table is built as a list of entries:
;
; .byte entrylen
; .byte errorcode
; .asciiz errormsg
;
; and, terminated by an entry with length zero that is returned if the
; error code could not be found.
;
.export __sys_oserrlist
.include "rp6502.inc"
.include "errno.inc"
;----------------------------------------------------------------------------
; Macros used to generate the list (may get moved to an include file?)
; Regular entry
.macro sys_oserr_entry code, msg
.local Start, End
Start:
.byte End - Start
.byte code
.asciiz msg
End:
.endmacro
; Sentinel entry
.macro sys_oserr_sentinel msg
.byte 0 ; Length is always zero
.byte 0 ; Code is unused
.asciiz msg
.endmacro
;----------------------------------------------------------------------------
; The error message table
.rodata
__sys_oserrlist:
sys_oserr_entry ENOENT , "No such file or directory"
sys_oserr_entry ENOMEM , "Out of memory"
sys_oserr_entry EACCES , "Permission denied"
sys_oserr_entry ENODEV , "No such device"
sys_oserr_entry EMFILE , "Too many open files"
sys_oserr_entry EBUSY , "Device or resource busy"
sys_oserr_entry EINVAL , "Invalid argument"
sys_oserr_entry ENOSPC , "No space left on device"
sys_oserr_entry EEXIST , "File exists"
sys_oserr_entry EAGAIN , "Try again"
sys_oserr_entry EIO , "I/O error"
sys_oserr_entry EINTR , "Interrupted system call"
sys_oserr_entry ENOSYS , "Function not implemented"
sys_oserr_entry ESPIPE , "Illegal seek"
sys_oserr_entry ERANGE , "Range error"
sys_oserr_entry EBADF , "Bad file number"
sys_oserr_entry ENOEXEC , "Exec format error"
sys_oserr_entry EUNKNOWN , "Unknown OS specific error"
sys_oserr_entry FR_DISK_ERR , "A hard error occurred in the low level disk I/O layer"
sys_oserr_entry FR_INT_ERR , "Assertion failed"
sys_oserr_entry FR_NOT_READY , "The physical drive cannot work"
sys_oserr_entry FR_NO_FILE , "Could not find the file"
sys_oserr_entry FR_NO_PATH , "Could not find the path"
sys_oserr_entry FR_INVALID_NAME , "The path name format is invalid"
sys_oserr_entry FR_DENIED , "Access denied due to prohibited access or directory full"
sys_oserr_entry FR_EXIST , "Access denied due to prohibited access"
sys_oserr_entry FR_INVALID_OBJECT , "The file/directory object is invalid"
sys_oserr_entry FR_WRITE_PROTECTED , "The physical drive is write protected"
sys_oserr_entry FR_INVALID_DRIVE , "The logical drive number is invalid"
sys_oserr_entry FR_NOT_ENABLED , "The volume has no work area"
sys_oserr_entry FR_NO_FILESYSTEM , "There is no valid FAT volume"
sys_oserr_entry FR_MKFS_ABORTED , "The f_mkfs() aborted due to any problem"
sys_oserr_entry FR_TIMEOUT , "Could not get a grant to access the volume within defined period"
sys_oserr_entry FR_LOCKED , "The operation is rejected according to the file sharing policy"
sys_oserr_entry FR_NOT_ENOUGH_CORE , "LFN working buffer could not be allocated"
sys_oserr_entry FR_TOO_MANY_OPEN_FILES , "Number of open files > FF_FS_LOCK"
sys_oserr_entry FR_INVALID_PARAMETER , "Given parameter is invalid"
sys_oserr_sentinel "Unknown error"

66
libsrc/rp6502/oserror.s Normal file
View File

@ -0,0 +1,66 @@
;
; 2000-05-17, Ullrich von Bassewitz
; 2022, ChaN
; 2023, Rumbledethumps
;
; int __fastcall__ __osmaperrno (unsigned char oserror);
;
; RP6502 will respond with a union of CC65 and FatFs errnos.
; This will map FatFs errors into the CC65 range for portable code.
EFATFS_START := 32
.include "rp6502.inc"
.include "errno.inc"
.code
___osmaperrno:
cmp #EFATFS_START
bmi @L2
ldx #ErrTabSize
@L1:
cmp ErrTab-2,x ; Search for the error code
beq @L3 ; Jump if found
dex
dex
bne @L1 ; Next entry
; Code not found, return EUNKNOWN
lda #<EUNKNOWN
ldx #>EUNKNOWN
@L2:
rts
; Found the code
@L3:
lda ErrTab-1,x
ldx #$00 ; High byte always zero
rts
.rodata
ErrTab:
.byte FR_DISK_ERR , EIO ; A hard error occurred in the low level disk I/O layer
; .byte FR_INT_ERR , EUNKNOWN ; Assertion failed
.byte FR_NOT_READY , EBUSY ; The physical drive cannot work
.byte FR_NO_FILE , ENOENT ; Could not find the file
.byte FR_NO_PATH , ENOENT ; Could not find the path
.byte FR_INVALID_NAME , EINVAL ; The path name format is invalid
.byte FR_DENIED , EACCES ; Access denied due to prohibited access or directory full
.byte FR_EXIST , EEXIST ; Access denied due to prohibited access
.byte FR_INVALID_OBJECT , EINVAL ; The file/directory object is invalid
.byte FR_WRITE_PROTECTED , EACCES ; The physical drive is write protected
.byte FR_INVALID_DRIVE , ENODEV ; The logical drive number is invalid
; .byte FR_NOT_ENABLED , EUNKNOWN ; The volume has no work area
; .byte FR_NO_FILESYSTEM , EUNKNOWN ; There is no valid FAT volume
; .byte FR_MKFS_ABORTED , EUNKNOWN ; The f_mkfs() aborted due to any problem
; .byte FR_TIMEOUT , EUNKNOWN ; Could not get a grant to access the volume within defined period
.byte FR_LOCKED , EBUSY ; The operation is rejected according to the file sharing policy
.byte FR_NOT_ENOUGH_CORE , ENOMEM ; LFN working buffer could not be allocated
.byte FR_TOO_MANY_OPEN_FILES , EMFILE ; Number of open files > FF_FS_LOCK
.byte FR_INVALID_PARAMETER , EINVAL ; Given parameter is invalid
ErrTabSize = (* - ErrTab)

14
libsrc/rp6502/phi2.c Normal file
View File

@ -0,0 +1,14 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ phi2(void)
{
return ria_call_int(RIA_OP_PHI2);
}

16
libsrc/rp6502/randomize.c Normal file
View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <stdlib.h>
// Non-standard cc65
void _randomize(void)
{
srand(ria_call_int(RIA_OP_LRAND));
}

31
libsrc/rp6502/read.c Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <unistd.h>
int __fastcall__ read(int fildes, void *buf, unsigned count)
{
int total = 0;
while (count)
{
unsigned blockcount = (count > 256) ? 256 : count;
int bytes_read = read_xstack(&((char *)buf)[total], blockcount, fildes);
if (bytes_read < 0)
{
return bytes_read;
}
total += bytes_read;
count -= bytes_read;
if (bytes_read < blockcount)
{
break;
}
}
return total;
}

17
libsrc/rp6502/read_xram.c Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ read_xram(unsigned buf, unsigned count, int fildes)
{
ria_push_int(buf);
ria_push_int(count);
ria_set_ax(fildes);
return ria_call_int_errno(RIA_OP_READ_XRAM);
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ read_xstack(void *buf, unsigned count, int fildes)
{
int i, ax;
ria_push_int(count);
ria_set_ax(fildes);
ax = ria_call_int_errno(RIA_OP_READ_XSTACK);
for (i = 0; i < ax; i++)
{
((char *)buf)[i] = ria_pop_char();
}
return ax;
}

90
libsrc/rp6502/ria.s Normal file
View File

@ -0,0 +1,90 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
.include "rp6502.inc"
.export _ria_push_long, _ria_push_int
.export _ria_pop_long, _ria_pop_int
.export _ria_set_axsreg, _ria_set_ax
.export _ria_call_int, _ria_call_long
.export _ria_call_int_errno, _ria_call_long_errno
.importzp sp, sreg
.import ___mappederrno, incsp1
.code
; void __fastcall__ ria_push_long(unsigned long val);
_ria_push_long:
ldy sreg+1
sty RIA_XSTACK
ldy sreg
sty RIA_XSTACK
; void __fastcall__ ria_push_int(unsigned int val);
_ria_push_int:
stx RIA_XSTACK
sta RIA_XSTACK
rts
; long __fastcall__ ria_pop_long(void);
_ria_pop_long:
jsr _ria_pop_int
ldy RIA_XSTACK
sty sreg
ldy RIA_XSTACK
sty sreg+1
rts
; int __fastcall__ ria_pop_int(void);
_ria_pop_int:
lda RIA_XSTACK
ldx RIA_XSTACK
rts
; void __fastcall__ ria_set_axsreg(unsigned long axsreg);
_ria_set_axsreg:
ldy sreg
sty RIA_SREG
ldy sreg+1
sty RIA_SREG+1
; void __fastcall__ ria_set_ax(unsigned int ax);
_ria_set_ax:
stx RIA_X
sta RIA_A
rts
; int __fastcall__ ria_call_int(unsigned char op);
_ria_call_int:
sta RIA_OP
jmp RIA_SPIN
; long __fastcall__ ria_call_long(unsigned char op);
_ria_call_long:
sta RIA_OP
jsr RIA_SPIN
ldy RIA_SREG
sty sreg
ldy RIA_SREG+1
sty sreg+1
rts
; int __fastcall__ ria_call_int_errno(unsigned char op);
_ria_call_int_errno:
sta RIA_OP
jsr RIA_SPIN
ldx RIA_X
bmi ERROR
rts
; long __fastcall__ ria_call_long_errno(unsigned char op);
_ria_call_long_errno:
jsr _ria_call_long
bmi ERROR
rts
ERROR:
lda RIA_ERRNO
jmp ___mappederrno

18
libsrc/rp6502/settime.c Normal file
View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <time.h>
int clock_settime(clockid_t clock_id, const struct timespec *tp)
{
ria_set_ax(clock_id);
ria_push_long(tp->tv_nsec);
ria_push_long(tp->tv_sec);
return ria_call_int_errno(RIA_OP_CLOCK_SETTIME);
}

16
libsrc/rp6502/stdin_opt.c Normal file
View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ stdin_opt(unsigned long ctrl_bits, unsigned char str_length)
{
ria_push_long(ctrl_bits);
ria_set_a(str_length);
return ria_call_int_errno(RIA_OP_STDIN_OPT);
}

26
libsrc/rp6502/sysremove.c Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <errno.h>
#include <string.h>
unsigned char __fastcall__ _sysremove(const char *name)
{
size_t namelen;
namelen = strlen(name);
if (namelen > 255)
{
return _mappederrno(EINVAL);
}
while (namelen)
{
ria_push_char(name[--namelen]);
}
return ria_call_int_errno(RIA_OP_UNLINK);
}

32
libsrc/rp6502/sysrename.c Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <errno.h>
#include <string.h>
unsigned char __fastcall__ _sysrename(const char *oldpath, const char *newpath)
{
size_t oldpathlen, newpathlen;
oldpathlen = strlen(oldpath);
newpathlen = strlen(newpath);
if (oldpathlen + newpathlen > 254)
{
return _mappederrno(EINVAL);
}
while (oldpathlen)
{
ria_push_char(oldpath[--oldpathlen]);
}
ria_push_char(0);
while (newpathlen)
{
ria_push_char(newpath[--newpathlen]);
}
return ria_call_int_errno(RIA_OP_RENAME);
}

31
libsrc/rp6502/write.c Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
#include <unistd.h>
int __fastcall__ write(int fildes, const void *buf, unsigned count)
{
int ax, total = 0;
while (count)
{
int blockcount = (count > 256) ? 256 : count;
ax = write_xstack(&((char *)buf)[total], blockcount, fildes);
if (ax < 0)
{
return ax;
}
total += ax;
count -= ax;
if (ax < blockcount)
{
break;
}
}
return total;
}

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ write_xram(unsigned buf, unsigned count, int fildes)
{
ria_push_int(buf);
ria_push_int(count);
ria_set_ax(fildes);
return ria_call_int_errno(RIA_OP_WRITE_XRAM);
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Rumbledethumps
*
* SPDX-License-Identifier: Zlib
* SPDX-License-Identifier: BSD-3-Clause
* SPDX-License-Identifier: Unlicense
*/
#include <rp6502.h>
int __fastcall__ write_xstack(const void *buf, unsigned count, int fildes)
{
unsigned i;
for (i = count; i;)
{
ria_push_char(((char *)buf)[--i]);
}
ria_set_ax(fildes);
return ria_call_int_errno(RIA_OP_WRITE_XSTACK);
}

40
libsrc/rp6502/xreg.s Normal file
View File

@ -0,0 +1,40 @@
; Copyright (c) 2023 Rumbledethumps
;
; SPDX-License-Identifier: Zlib
; SPDX-License-Identifier: BSD-3-Clause
; SPDX-License-Identifier: Unlicense
; CC65 will promote variadic char arguments to int. It will not demote longs.
; int __cdecl__ xreg(char device, char channel, unsigned char address, ...);
.export _xreg
.importzp sp
.import addysp, _ria_call_int_errno
.include "rp6502.inc"
.code
.proc _xreg
; save variadic size in X
tya
tax
@copy: ; copy stack
dey
lda (sp),y
sta RIA_XSTACK
tya
bne @copy
; recover variadic size and move sp
txa
tay
jsr addysp
; run RIA operation
lda #RIA_OP_XREG
jmp _ria_call_int_errno
.endproc

View File

@ -346,6 +346,10 @@ static void SetSys (const char* Sys)
NewSymbol ("__KIM1__", 1);
break;
case TGT_RP6502:
NewSymbol ("__RP6502__", 1);
break;
default:
AbEnd ("Invalid target name: '%s'", Sys);

View File

@ -303,6 +303,10 @@ static void SetSys (const char* Sys)
DefineNumericMacro ("__KIM1__", 1);
break;
case TGT_RP6502:
DefineNumericMacro ("__RP6502__", 1);
break;
default:
AbEnd ("Unknown target system '%s'", Sys);
}

View File

@ -173,6 +173,7 @@ static const TargetEntry TargetMap[] = {
{ "pce", TGT_PCENGINE },
{ "pet", TGT_PET },
{ "plus4", TGT_PLUS4 },
{ "rp6502", TGT_RP6502 },
{ "sim6502", TGT_SIM6502 },
{ "sim65c02", TGT_SIM65C02 },
{ "supervision", TGT_SUPERVISION },
@ -221,6 +222,7 @@ static const TargetProperties PropertyTable[TGT_COUNT] = {
{ "cx16", CPU_65C02, BINFMT_BINARY, CTPET },
{ "sym1", CPU_6502, BINFMT_BINARY, CTNone },
{ "kim1", CPU_6502, BINFMT_BINARY, CTNone },
{ "rp6502", CPU_65C02, BINFMT_BINARY, CTNone },
};
/* Target system */

View File

@ -88,6 +88,7 @@ typedef enum {
TGT_CX16,
TGT_SYM1,
TGT_KIM1,
TGT_RP6502,
TGT_COUNT /* Number of target systems */
} target_t;