Merge pull request #2268 from picocomputer/master

add rp6502 target
This commit is contained in:
Bob Andrews 2023-11-27 17:53:43 +01:00 committed by GitHub
commit 7e6399d439
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1163 additions and 0 deletions

97
asminc/rp6502.inc Normal file
View File

@ -0,0 +1,97 @@
; Picocomputer 6502 general defines
; 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

34
cfg/rp6502.cfg Normal file
View File

@ -0,0 +1,34 @@
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__;
}

View File

@ -175,6 +175,9 @@
<tag><htmlurl url="plus4.html" name="plus4.html"></tag>
Topics specific to the Commodore Plus/4.
<tag><htmlurl url="rp6502.html" name="rp6502.html"></tag>
Topics specific to the Picocomputer 6502.
<tag><htmlurl url="supervision.html" name="supervision.html"></tag>
Topics specific to the Watara Supervision Console.

96
doc/rp6502.sgml Normal file
View File

@ -0,0 +1,96 @@
<!doctype linuxdoc system>
<article>
<title>Picocomputer 6502 - specific information for cc65
<author><url url="mailto:uz@cc65.org" name="Ullrich von Bassewitz">
<abstract>
An overview over the Picocomputer 6502 and its interfaces to the cc65 C
compiler.
</abstract>
<!-- Table of contents -->
<toc>
<!-- Begin the document -->
<sect>Overview<p>
The Picocomputer 6502 is a modern W65C02S computer with a custom operating
system designed to be POSIX-like. The reference design includes a W65C02S,
W65C22S, RP6502-RIA, and optionally a RP6502-VGA. Peripheral devices like
keyboards, mice, and flash storage are connected by USB to the RP6502-RIA.
Audio is generated by the RP6502-RIA. Video is generated by the RP6502-VGA.
<sect>Binary format<p>
The standard binary output format generated by the linker for the RP6502 target
is a plain machine language program without any prefix or postfix.
The RP6502 Integrated Development Environment, based on Visual Studio Code,
will convert the cc65 binary output into RP6502 ROM files that can be loaded
directly from the RP6502 monitor or installed on the RIA to be loaded at boot.
<sect>Memory layout<p>
<descrip>
<tag/Stack/
The C run-time stack is located at &dollar;FEFF, and grows downward.
<tag/Heap/
The C heap is located at the end of the program, and grows toward the C
run-time stack.
<tag/RAM/
RAM is located at &dollar;0000 - &dollar;FEFF. Default binaries load and
start at &dollar;0200.
<tag/ROM/
The RP6502 is designed with no ROM in the 6502 address space.
<tag/VIA/
A Versatile Interface Adapter (6522) is 16 registers located
at &dollar;FFD0.
<tag/RIA/
The RP6502 Interface Adapter is 32 registers located at &dollar;FFE0.
<tag/User/
User I/O expansion is from &dollar;FF00 to &dollar;FFCF.
</descrip><p>
<sect>Platform-specific header files<p>
Programs containing RP6502-specific code may use the <tt/rp6502.h/ or
<tt/rp6502.inc/ include files.
<sect>License<p>
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:
<enum>
<item> 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.
<item> Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
<item> This notice may not be removed or altered from any source
distribution.
</enum>
</article>

264
include/rp6502.h Normal file
View File

@ -0,0 +1,264 @@
/*****************************************************************************/
/* */
/* rp6502.h */
/* */
/* Picocomputer 6502 */
/* */
/* */
/* 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. */
/* */
/*****************************************************************************/
#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 \

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

@ -0,0 +1,8 @@
#include <rp6502.h>
#include <errno.h>
int __fastcall__ close (int fd)
{
ria_set_ax (fd);
return ria_call_int_errno (RIA_OP_CLOSE);
}

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

@ -0,0 +1,6 @@
#include <rp6502.h>
int __fastcall__ codepage (void)
{
return ria_call_int (RIA_OP_CODEPAGE);
}

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

@ -0,0 +1,51 @@
;
; 2023, Rumbledethumps
;
; 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

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

@ -0,0 +1,10 @@
#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);
}

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

@ -0,0 +1,12 @@
#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,13 @@
#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,16 @@
#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;
}

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

@ -0,0 +1,14 @@
;
; 2023, Rumbledethumps
;
.constructor initenv, 24
.import __environ, __envcount, __envsize
.segment "ONCE"
.proc initenv
rts
.endproc

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

@ -0,0 +1,50 @@
;
; 2023, Rumbledethumps
;
; Enables the C IRQ tools
.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

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

@ -0,0 +1,6 @@
#include <rp6502.h>
long __fastcall__ lrand (void)
{
return ria_call_long (RIA_OP_LRAND);
}

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

@ -0,0 +1,11 @@
#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);
}

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

@ -0,0 +1,15 @@
;
; 2023, Rumbledethumps
;
; No arguments
.constructor initmainargs, 24
.import __argc, __argv
.segment "ONCE"
.proc initmainargs
rts
.endproc

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

@ -0,0 +1,16 @@
#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)

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

@ -0,0 +1,6 @@
#include <rp6502.h>
int __fastcall__ phi2 (void)
{
return ria_call_int (RIA_OP_PHI2);
}

View File

@ -0,0 +1,7 @@
#include <rp6502.h>
#include <stdlib.h>
void _randomize (void)
{
srand (ria_call_int (RIA_OP_LRAND));
}

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

@ -0,0 +1,20 @@
#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;
}

View File

@ -0,0 +1,9 @@
#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,13 @@
#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;
}

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

@ -0,0 +1,89 @@
;
; 2023, Rumbledethumps
;
; Helpers for building API shims
.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

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

@ -0,0 +1,10 @@
#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);
}

View File

@ -0,0 +1,9 @@
#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);
}

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

@ -0,0 +1,16 @@
#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);
}

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

@ -0,0 +1,21 @@
#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);
}

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

@ -0,0 +1,20 @@
#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,9 @@
#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,11 @@
#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);
}

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

@ -0,0 +1,37 @@
;
; 2023, Rumbledethumps
;
; 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;