VxKernel 0.6.0-17 : Add RTC driver + prepare FS support

@add
<> include/vhex/display/draw/rect
  | add filled rectangle API
<> src/display/draw/drect
  | add filled rectangle drawing API
<> board/fxcg50/
  | add devices special section (WIP)
<> include/vhex/device
  | add device structure (WIP)
<> include/vhex/driver/mpu/sh/sh7305/
  | [intc] add primitive which allow dummy default interrupt handler
  | [rtc]  add complete RTC hardware structure
  | [rtc]  add hardware-level kernel API
<> include/vhex/fs
  | add file system abstraction API (WIP)
  | add Fugue FAT file system abstraction API (WIP)
<> include/vhex/rtc
  | add RTC user-level API
  | add driver-level interface
  | add kernel-level types
<> src/fs
  | add base Fugue abstraction (WIP)
  | add libc functions (WIP)

@update
<> include/vhex/display/draw/text
  | merge halign and valign argument
  | add special alignment flags
<> include/vhex/driver
  | add RTC driver flags
<> include/vhex/driver/mpu/sh/sh7305/cpg
  | rename weird field
  | add Spread Spectrum emulator field
  | properly expand LSTATS register
<> src/driver/mpu/sh/sh7305
  | [intc] allow user-level interrupt handler installation
  | [intc] expose common interrupt handler
  | [rtc] add RTC entire driver
<> src/driver/scree/r61524
  | use complete VRAM instead of fragmented render

@fix
<> src/display
  | [text] fix height for text display geometry
  | [text] fix alignment calculation
  | [dclear] fix geometry support
<> src/driver/mpu/sh/sh7305
  | [cpg] fix driver installation
  | [cpg] fix driver spread spectrum
  | [cpg] fix driver declaration
  | [tmu] fix exception with the profiling primitives
This commit is contained in:
Yann MAGNIN 2022-08-08 20:19:00 +02:00
parent 585254cb2e
commit e8e63016d5
35 changed files with 1251 additions and 46 deletions

View File

@ -9,7 +9,8 @@ modules = [
'hypervisor',
'keyboard',
'kmalloc',
'timer'
'timer',
'rtc',
]
[drivers]

View File

@ -60,6 +60,13 @@ SECTIONS
_vhex_modules_end = . ;
} > userram
/* Exposed device interfaces (.vhex.device) */
.vhex.device : {
_vhex_devices_start = . ;
KEEP(*(.vhex.device));
_vhex_devices_end = . ;
} > userram
/* Read-only sections */
.rodata : {
/* Read-Only data */

68
include/vhex/device.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef __VHEX_DEVICE__
# define __VHEX_DEVICE__
#include <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
struct vhex_device
{
/* device name */
const char * const name;
/* device flags */
byte_union(flags,
uint8_t :1;
uint8_t :1;
uint8_t :1;
uint8_t :1;
uint8_t :1;
uint8_t :1;
uint8_t :1;
uint8_t FS :1;
);
/* device primitives */
struct {
int (*init)(void);
int (*open)(void **data, const char *pathname, int flags, int mode);
ssize_t (*write)(void *data, const void *buf, size_t size);
ssize_t (*read)(void *data, void *buf, size_t size);
off_t (*lseek)(void *data, off_t offset, int whence);
int (*close)(void *data);
int (*quit)(void);
} primitives;
};
/* VHEX_DECLARE_DEVICE(): Declare a device for the kernel
Use this macro to declare a device by passing it the name of a
vhex_device structure. This macro moves the structure to the
`.vhex.device` sections, which are automatically traversed at startup. */
#define VHEX_DECLARE_DEVICE(name) \
VSECTION(".vhex.device") extern struct vhex_device name;
//---
// Internal driver control
//
// The following data is exposed for introspection and debugging purposes; it
// is not part of the vhex API. There is *no stability guarantee* that the
// following types and functions will remain unchanged in future minor and
// patch versions.
//---
/* Number of drivers in the (vhex_drivers) array */
#define vhex_device_count() \
((struct vhex_device *)&vhex_devices_end \
- (struct vhex_device *)&vhex_devices_start)
/* driver table */
#define vhex_device_table() \
((struct vhex_device *)&vhex_devices_start)
/* provided by the linker script */
extern uintptr_t vhex_devices_start;
extern uintptr_t vhex_devices_end;
#endif /* __VHEX_DEVICE__ */

View File

@ -43,7 +43,7 @@ struct vhex_driver
/* default flags for the driver */
byte_union(flags,
uint8_t :1;
uint8_t RTC :1;
uint8_t KEYBOARD :1;
uint8_t TIMER :1;
uint8_t DISPLAY :1;

View File

@ -14,7 +14,7 @@
/* sh7305_cpg - Clock Pulse Generator registers
Fields marked with [*] don't have the meaning described in the SH7724
documentation. */
struct sh7305_cpg
struct __sh7305_cpg
{
lword_union(FRQCR,
uint32_t KICK :1; /* Flush FRQCRA modifications */
@ -25,7 +25,7 @@ struct sh7305_cpg
uint32_t SFC :4; /* Sphi divider 1 [*] */
uint32_t BFC :4; /* Bphi divider 1 [*] */
uint32_t :4;
uint32_t P1FC :4; /* Pphi divider 1 [*] */
uint32_t PFC :4; /* Pphi divider 1 [*] */
);
pad(0x4);
@ -83,7 +83,8 @@ struct sh7305_cpg
lword_union(SSCGCR,
uint32_t SSEN :1; /* Spread Spectrum Enable */
uint32_t :31;
uint32_t :30;
uint32_t SSEN_EMU:1; /* Emulateur enable */
);
pad(0x8);
@ -95,11 +96,14 @@ struct sh7305_cpg
);
pad(0x0c);
uint32_t LSTATS;
lword_union(LSTATS,
uint32_t :31;
uint32_t FRQF : 1; /* frequency changing status */
);
} VPACKED(4);
#define SH7305_CPG (*((volatile struct sh7305_cpg *)0xa4150000))
#define SH7305_CPG (*((volatile struct __sh7305_cpg *)0xa4150000))
//---
// kernel-level API

View File

@ -465,4 +465,7 @@ extern void *sh7305_intc_install_inth(int blockid, void *gate, size_t size);
/* sh7305_intc_priority() : set the interrupt name priority */
extern int sh7305_intc_priority(int intname, int level);
/* sh7305_intc_generic_handler() : install generic interrupt handler */
extern void *sh7305_intc_generic_handler(int event_code, void *user_inth);
#endif /* __VHEX_ARCH_SH7305_INTC__ */

View File

@ -0,0 +1,135 @@
#ifndef __VHEX_DRIVER_MPU_SH_SH7305_RTC__
# define __VHEX_DRIVER_MPU_SH_SH7305_RTC__
#include <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
//---
// Hybrid SH7705-SH7305 Real-Time Clock. Refer to:
// "Renesas SH7705 Group Hardware Manual"
// Section 15: "Real-Time Clock (RTC)"
// "Renesas SH7724 User's Manual: Hardware"
// Section 28: "Real-Time Clock (RTC)"
//---
/* rtc_BCD2_t - a 2-digit BCD counter with a 1-byte gap */
typedef struct
{
byte_union(,
uint8_t TENS :4;
uint8_t ONES :4;
);
pad(1);
} VPACKED(2) rtc_BCD2_t;
/* sh7305_rtc - Date and time access, RTC control */
struct __sh7305_rtc_s
{
uint8_t const R64CNT; /* A 64-Hz counter */
pad(1);
rtc_BCD2_t RSECCNT; /* Second count */
rtc_BCD2_t RMINCNT; /* Minute count */
rtc_BCD2_t RHRCNT; /* Hour count */
uint8_t RWKCNT; /* Day of week, must be in [0..6] */
pad(1);
rtc_BCD2_t RDAYCNT; /* Day count */
rtc_BCD2_t RMONCNT; /* Month count */
word_union(RYRCNT, /* Year count */
uint THOUSANDS :4;
uint HUNDREDS :4;
uint TENS :4;
uint ONES :4;
);
pad(12); /* Alarm registers... */
byte_union(RCR1,
uint8_t CF :1; /* Carry flag */
uint8_t :2;
uint8_t CIE :1; /* Carry interrupt enable */
uint8_t AIE :1; /* Alarm interrupt enable */
uint8_t :2;
uint8_t AF :1; /* Alarm flag */
);
pad(1);
byte_union(RCR2,
uint8_t PEF :1; /* Periodic interrupt flag */
uint8_t PES :3; /* Periodic interrupt interval */
uint8_t :1;
uint8_t ADJ :1; /* 30-second adjustment */
uint8_t RESET :1; /* Reset trigger */
uint8_t START :1; /* Start bit */
);
pad(1);
byte_union(RCR3,
uint8_t BEN :1; /* Periodic interrupt flag */
uint8_t :7;
);
pad(1);
} VPACKED(4);
#define SH7305_RTC (*((volatile struct __sh7305_rtc_s *)0xa413fec0))
//---
// RTC periodic interrupt
// The real-time clock produces a regular interrupt which may be used as a
// timer with a maximum frequency of 256 Hz. It is also useful to check
// that the clock settings (see <gint/clock.h>) are properly detected, by
// comparing the detected frequencies with the RTC.
//---
/* Possible frequency settings for the RTC's interrupt */
enum
{
RTC_500mHz = 7,
RTC_1Hz = 6,
RTC_2Hz = 5,
RTC_4Hz = 4,
RTC_16Hz = 3,
RTC_64Hz = 2,
RTC_256Hz = 1,
RTC_NONE = 0,
};
/* rtc_call: Indirect call with up to 4 register arguments */
struct rtc_call {
void *function;
uint32_t args[4];
};
/* RTC_CALL(): Build an callback from function and arguments */
#define RTC_CALL(fct, ...) \
(struct rtc_call){ \
.function = (void*)fct, \
.args = { __VA_ARGS__ } \
}
/* rtc_periodic_enable(): Enable the periodic interrupt
This function sets up the periodic interrupt to invoke the provided callback
regularly. As with timers, the callback must return either TIMER_CONTINUE or
TIMER_STOP.
Note that the timing of the first callback is always uncertain. A 1 Hz timer
set up when half of the current second is already elapsed will be called for
the first time after only 500 ms, for instance.
@frequency Periodic interrupt frequency
@callback Function to call back at the specified frequency
Returns true on success, false if the interrupt is already in use. */
extern bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback);
/* rtc_periodic_disable(): Stop the periodic interrupt
This has the same effect as returning TIMER_STOP from the callback, or
setting RTC_NONE as the parameter for rtc_periodic_enable(). */
extern void sh7305_rtc_periodic_disable(void);
#endif /* __VHEX_DRIVER_MPU_SH_SH7305_RTC__ */

34
include/vhex/fs.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef __VHEX_FS_INFORMATION__
# define __VHEX_FS_INFORMATION__
#include <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
#include <vhex/device.h>
/* define the default number of file that can be oppened in the same time */
#ifndef VHEX_NB_FILE
# define VHEX_NB_FILE 8
#endif /* VHEX_NB_FILE */
/* internal file system information */
struct __fs_info {
struct vhex_device fs;
void *table[VHEX_NB_FILE];
};
extern struct __fs_info fs_info;
//---
// Internal API
//---
/* fs_table_reserve() : reserve file descriptor */
extern int fs_table_reserve(void **data);
/* fs_table_find() : find device-specific data */
extern int fs_table_find(void **data, int fd);
/* fs_table_remove() : remove file descriptor */
extern int fs_table_remove(int fd);
#endif /* __VHEX_FS_INFORMATION__ */

12
include/vhex/fs/fugue.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __VHEX_FS_FUGUE__
# define __VHEX_FS_FUGUE__
#include <vhex/defs/types.h>
extern int fugue_open(void **data, const char *pathname, int flags, int mode);
extern ssize_t fugue_write(void *data, const void *buf, size_t size);
extern ssize_t fugue_read(void *data, void *buf, size_t size);
extern off_t fugue_lseek(void *data, off_t offset, int whence);
extern int fugue_close(void *data);
#endif /* __VHEX_FS_FUGUE__ */

16
include/vhex/rtc.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __VHEX_DRIVER_RTC__
# define __VHEX_DRIVER_RTC__
#include <vhex/rtc/types.h>
/* rtc_get_time(): Read the current time from the RTC
@time Pointer to rtc_time_t structure (needs not be initialized) */
extern int rtc_get_time(rtc_time_t *time);
/* rtc_set_time(): Set current time in the RTC
If [time->week_day] is not in the valid range, it is set to 0. Other fields
are not checked. R64CNT cannot be set to [time->ticks] is ignored.
@time Pointer to new time */
extern int rtc_set_time(rtc_time_t const *time);
#endif /* __VHEX_DRIVER_RTC__ */

View File

@ -0,0 +1,13 @@
#ifndef __VHEX_TIMER_INTERFACE__
# define __VHEX_TIMER_INTERFACE__
#include <vhex/rtc/types.h>
/* rtc_drv_interface - driver interface */
struct rtc_drv_interface
{
int (*rtc_get_time)(rtc_time_t *time);
int (*rtc_set_time)(rtc_time_t const *time);
};
#endif /* __VHEX_TIMER_INTERFACE__ */

24
include/vhex/rtc/types.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __VHEX_RTC_TYPES__
# define __VHEX_RTC_TYPES__
#include <stdint.h>
/* rtc_time_t: A point in time, representable in the RTC registers
WARNING: A copy of this definition is used in fxlibc, make sure to keep it
in sync. (We don't install kernel headers before compiling the fxlibc, it's
kind of a nightmare for the modest build system.) */
typedef struct
{
uint16_t year; /* Years (exact value, e.g. 2018) */
uint8_t week_day; /* Day of week, (0=Sunday, 6=Saturday) */
uint8_t month; /* Month (0..11) */
uint8_t month_day; /* Day of month (1..31) */
uint8_t hours; /* Hour (0..23) */
uint8_t minutes; /* Minute (0..59) */
uint8_t seconds; /* Second (0..59) */
uint8_t ticks; /* 128-Hz sub-second counter (0...127) */
} rtc_time_t;
#endif /* __VHEX_RTC_TYPES__ */

View File

@ -9,12 +9,17 @@
/* dclear_draw() : real drawing algorithm */
void dclear_render(dsurface_t *surface, uint32_t color)
{
uint32_t *vram = surface->vram;
for (size_t i = 0; i < surface->width * (surface->height/2); ++i)
vram[i] = color;
#if 0
uint32_t *vram;
int size = (surface->y1 == 220) ? 792 : 1980;
vram = surface->vram;
for (int i = 0; i < size; ++i)
vram[i] = color;
#endif
}
//---

View File

@ -21,7 +21,7 @@ void cpg_clock_freq(struct cpg_clock_frequency *freq)
int divb = CPG.FRQCR.BFC;
int divi = CPG.FRQCR.IFC;
int divs = CPG.FRQCR.SFC;
int divp = CPG.FRQCR.P1FC;
int divp = CPG.FRQCR.PFC;
freq->Bphi_div = 1 << (divb + 1);
freq->Iphi_div = 1 << (divi + 1);
@ -47,25 +47,143 @@ void cpg_clock_freq(struct cpg_clock_frequency *freq)
//---
struct cpg_ctx {
uint32_t SSCGCR;
struct __sh7305_cpg hw;
};
/* __cpg_configure() : configure the CPG */
static void __cpg_configure(struct cpg_ctx *state)
{
(void)state;
/* Configure the all bus divier and multiplicator
<> PLL : 232.31Mhz (x16)
<> Iphi (CPU) : 116.15Mhz (/2)
<> Sphi (SuperH) : 58.07Mhz (/4)
<> Bphi (BSC) : 58.07Mhz (/4)
<> Pphi (peripheral) : 29.03Mhz (/8)
*/
state->hw.FRQCR.STC = 15;
state->hw.FRQCR.IFC = 0;
state->hw.FRQCR.SFC = 1;
state->hw.FRQCR.BFC = 1;
state->hw.FRQCR.PFC = 2;
/* Configure FSI clock (disable by default) */
state->hw.FSICLKCR.CLKSTP = 1;
/* Configure DD clock (disable by default) */
state->hw.DDCLKCR.CLKSTP = 1;
/* Configure USB clock (disable by default) */
state->hw.USBCLKCR.CLKSTP = 1;
/* Configure PLL and FLL multiplier
<> enable PLL
<> enable FLL
<> disable CKO output stop
*/
state->hw.PLLCR.PLLE = 1;
state->hw.PLLCR.FLLE = 1;
state->hw.PLLCR.CKOFF = 0;
/* Configure PLL multiplication ratio (disable by default) */
state->hw.PLL2CR.MUL = 0;
/* Configure SPU (disable by default) */
state->hw.SPUCLKCR.CLKSTP = 1;
/* Configure Spread Spectrum (force disable) */
state->hw.SSCGCR.SSEN_EMU = 0;
state->hw.SSCGCR.SSEN = 0;
/* Configure FLL division/multiplicator
<> force FLL multiplication Ratio with x(1/2)
<> use 1017 (default value of the module) as multiplicator wich will
give us ~16Mhz (Casio use 900 instead of 1017 wich is ~14Mhz):
( 32768 * 1017 ) / 2 = 16 662 528 Hz
( 32768 * 900 ) / 2 = 14 745 600 Hz
*/
state->hw.FLLFRQ.SELXM = 1;
state->hw.FLLFRQ.FLF = 1017;
}
/* __cpg_hsave() : save hardware information */
static void __cpg_hsave(struct cpg_ctx *state)
{
(void)state;
state->hw.FRQCR.STC = SH7305_CPG.FRQCR.STC;
state->hw.FRQCR.IFC = SH7305_CPG.FRQCR.IFC;
state->hw.FRQCR.SFC = SH7305_CPG.FRQCR.SFC;
state->hw.FRQCR.BFC = SH7305_CPG.FRQCR.BFC;
state->hw.FRQCR.PFC = SH7305_CPG.FRQCR.PFC;
state->hw.FSICLKCR.DIVB = SH7305_CPG.FSICLKCR.DIVB;
state->hw.FSICLKCR.CLKSTP = SH7305_CPG.FSICLKCR.CLKSTP;
state->hw.FSICLKCR.SRC = SH7305_CPG.FSICLKCR.SRC;
state->hw.FSICLKCR.DIVA = SH7305_CPG.FSICLKCR.DIVA;
state->hw.DDCLKCR.CLKSTP = SH7305_CPG.DDCLKCR.CLKSTP;
state->hw.DDCLKCR.SRC = SH7305_CPG.DDCLKCR.SRC;
state->hw.DDCLKCR.DIV = SH7305_CPG.DDCLKCR.DIV;
state->hw.USBCLKCR.CLKSTP = SH7305_CPG.USBCLKCR.CLKSTP;
state->hw.PLLCR.PLLE = SH7305_CPG.PLLCR.PLLE;
state->hw.PLLCR.FLLE = SH7305_CPG.PLLCR.FLLE;
state->hw.PLLCR.CKOFF = SH7305_CPG.PLLCR.CKOFF;
state->hw.PLL2CR.MUL = SH7305_CPG.PLL2CR.MUL;
state->hw.SPUCLKCR.CLKSTP = SH7305_CPG.SPUCLKCR.CLKSTP;
state->hw.SPUCLKCR.SRC = SH7305_CPG.SPUCLKCR.SRC;
state->hw.SPUCLKCR.DIV = SH7305_CPG.SPUCLKCR.DIV;
state->hw.SSCGCR.SSEN = SH7305_CPG.SSCGCR.SSEN;
state->hw.SSCGCR.SSEN_EMU = SH7305_CPG.SSCGCR.SSEN_EMU;
state->hw.FLLFRQ.SELXM = SH7305_CPG.FLLFRQ.SELXM;
state->hw.FLLFRQ.FLF = SH7305_CPG.FLLFRQ.FLF;
}
/* __cpg_hrestore() : restore hardware information */
static void __cpg_hrestore(struct cpg_ctx *state)
{
(void)state;
SH7305_CPG.FRQCR.STC = state->hw.FRQCR.STC;
SH7305_CPG.FRQCR.IFC = state->hw.FRQCR.IFC;
SH7305_CPG.FRQCR.SFC = state->hw.FRQCR.SFC;
SH7305_CPG.FRQCR.BFC = state->hw.FRQCR.BFC;
SH7305_CPG.FRQCR.PFC = state->hw.FRQCR.PFC;
SH7305_CPG.FSICLKCR.DIVB = state->hw.FSICLKCR.DIVB;
SH7305_CPG.FSICLKCR.CLKSTP = state->hw.FSICLKCR.CLKSTP;
SH7305_CPG.FSICLKCR.SRC = state->hw.FSICLKCR.SRC;
SH7305_CPG.FSICLKCR.DIVA = state->hw.FSICLKCR.DIVA;
SH7305_CPG.DDCLKCR.CLKSTP = state->hw.DDCLKCR.CLKSTP;
SH7305_CPG.DDCLKCR.SRC = state->hw.DDCLKCR.SRC;
SH7305_CPG.DDCLKCR.DIV = state->hw.DDCLKCR.DIV;
SH7305_CPG.USBCLKCR.CLKSTP = state->hw.USBCLKCR.CLKSTP;
SH7305_CPG.PLLCR.PLLE = state->hw.PLLCR.PLLE;
SH7305_CPG.PLLCR.FLLE = state->hw.PLLCR.FLLE;
SH7305_CPG.PLLCR.CKOFF = state->hw.PLLCR.CKOFF;
SH7305_CPG.PLL2CR.MUL = state->hw.PLL2CR.MUL;
SH7305_CPG.SPUCLKCR.CLKSTP = state->hw.SPUCLKCR.CLKSTP;
SH7305_CPG.SPUCLKCR.SRC = state->hw.SPUCLKCR.SRC;
SH7305_CPG.SPUCLKCR.DIV = state->hw.SPUCLKCR.DIV;
SH7305_CPG.SSCGCR.SSEN = state->hw.SSCGCR.SSEN;
SH7305_CPG.SSCGCR.SSEN_EMU = state->hw.SSCGCR.SSEN_EMU;
SH7305_CPG.FLLFRQ.SELXM = state->hw.FLLFRQ.SELXM;
SH7305_CPG.FLLFRQ.FLF = state->hw.FLLFRQ.FLF;
SH7305_CPG.FRQCR.KICK = 1;
while (SH7305_CPG.LSTATS.FRQF != 0) { __asm__ volatile ("nop"); }
SH7305_CPG.PLL2CR.KICK = 1;
while (SH7305_CPG.LSTATS.FRQF != 0) { __asm__ volatile ("nop"); }
}
struct vhex_driver drv_cpg = {
@ -75,4 +193,4 @@ struct vhex_driver drv_cpg = {
.configure = (void*)&__cpg_configure,
.state_size = sizeof(struct cpg_ctx)
};
VHEX_DECLARE_DRIVER(03, drv_cpu);
VHEX_DECLARE_DRIVER(03, drv_cpg);

View File

@ -1,5 +0,0 @@
#include <vhex/driver/mpu/sh/sh7305/intc.h>
#include <vhex/defs/types.h>
#include <string.h>

View File

@ -120,6 +120,24 @@ void *sh7305_intc_install_inth(int event_code, void *gate, size_t size)
);
}
/* sh7305_intc_generic_handler() : install generic interrupt handler */
void *sh7305_intc_generic_handler(int event_code, void *user_inth)
{
extern void vhex_sh7305_intc_generic_handler(void);
void *h = sh7305_intc_install_inth(
event_code,
sh7305_intc_generic_handler,
32
);
if(!h) return false;
*(void **)(h + 28) = user_inth;
return h;
}
//---
// hardware configuration call
//---

View File

@ -66,3 +66,21 @@ _vhex_inth_sh7305:
.first_entry:
/* _vhex_sh7305_intc_generic_handler: Standard interrupt handler
This is a generic interrupt handler that calls back into a C function,
useful for complex handling or simple drivers that benefit more from
simplicity than razor-sharp performance. */
.section .vhex.blocks, "ax"
.align 4
.global _vhex_sh7305_intc_generic_handler /* 32 bytes */
_vhex_sh7305_intc_generic_handler:
mov.l 1f, r1
jmp @r1
mov r0, r4
.zero 22 /* Indirect call to be made */
1: .long 0 /* Address of the runtime */

View File

@ -6,7 +6,6 @@
/* define the private KeyScan context structure */
struct keysc_ctx {
struct __sh7305_keysc_s keysc;
uint16_t iprf;
};
/* hardware configuration call */

View File

@ -0,0 +1,231 @@
#include <vhex/driver/mpu/sh/sh7305/rtc.h>
#include <vhex/driver/mpu/sh/sh7305/intc.h>
#include <vhex/rtc/interface.h>
#include <vhex/driver.h>
#include <string.h>
//---
// RTC periodic interrupt
//---
static struct rtc_call rtc_call;
/* rtc_periodic interrupt() : internal interrupt handler */
static void sh7305_rtc_periodic_inth(void)
{
int (*routine)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t
) = rtc_call.function;
int rc = routine(
rtc_call.args[0],
rtc_call.args[1],
rtc_call.args[2],
rtc_call.args[3]
);
/* Clear the interrupt flag */
do SH7305_RTC.RCR2.PEF = 0;
while(SH7305_RTC.RCR2.PEF);
/* Stop the interrupt if the callback returns non-zero */
if(rc) sh7305_rtc_periodic_disable();
}
/* rtc_periodic_enable(): Enable the periodic interrupt */
bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback)
{
/* Refuse to override an existing interrupt */
if(SH7305_RTC.RCR2.PES != RTC_NONE) return false;
if(frequency == RTC_NONE)
{
sh7305_rtc_periodic_disable();
return true;
}
/* Temporarily disable the interrupt and set up the callback */
SH7305_RTC.RCR2.PES = RTC_NONE;
memcpy(&rtc_call, &callback, sizeof(struct rtc_call));
/* Clear the interrupt flag */
do SH7305_RTC.RCR2.PEF = 0;
while(SH7305_RTC.RCR2.PEF);
/* Enable the interrupt */
SH7305_RTC.RCR2.PES = frequency;
return true;
}
/* rtc_periodic_disable(): Stop the periodic interrupt */
void sh7305_rtc_periodic_disable(void)
{
SH7305_RTC.RCR2.PES = RTC_NONE;
}
//---
// Define driver information
//---
struct rtc_ctx {
struct __sh7305_rtc_s rtc;
};
/* __rtc_configure() : configure the RTC */
static void __rtc_configure(struct rtc_ctx *state)
{
/* Clear and disable the carry and alamr interrupts */
state->rtc.RCR1.CF = 0;
state->rtc.RCR1.CIE = 0;
state->rtc.RCR1.AIE = 0;
state->rtc.RCR1.AF = 0;
/* Disable the periodic interrupt flag */
state->rtc.RCR2.PEF = 0;
state->rtc.RCR2.PES = RTC_NONE;
state->rtc.RCR2.ADJ = 0;
state->rtc.RCR2.RESET = 1;
state->rtc.RCR2.START = 1;
/* Disable year alarm check */
state->rtc.RCR3.BEN = 0;
/* set the interrupt level (max) */
sh7305_intc_priority(INTC_RTC_ATI, 0);
sh7305_intc_priority(INTC_RTC_CUI, 0);
sh7305_intc_priority(INTC_RTC_PRI, 1);
/* intall the RTC interupt handler */
sh7305_intc_generic_handler(0xaa0, &sh7305_rtc_periodic_inth);
}
/* __rtc_hsave() : save hardware information */
static void __rtc_hsave(struct rtc_ctx *state)
{
/* stop as soon as possible RTC counters */
state->rtc.RCR2.START = SH7305_RTC.RCR2.START;
SH7305_RTC.RCR2.START = 0;
state->rtc.RCR1.CF = SH7305_RTC.RCR1.CF;
state->rtc.RCR1.CIE = SH7305_RTC.RCR1.CIE;
state->rtc.RCR1.AIE = SH7305_RTC.RCR1.AIE;
state->rtc.RCR1.AF = SH7305_RTC.RCR1.AF;
state->rtc.RCR2.PEF = SH7305_RTC.RCR2.PEF;
state->rtc.RCR2.PES = SH7305_RTC.RCR2.PES;
state->rtc.RCR2.ADJ = SH7305_RTC.RCR2.ADJ;
state->rtc.RCR3.BEN = SH7305_RTC.RCR3.BEN;
}
/* __rtc_hrestore() : restore hardware information */
static void __rtc_hrestore(struct rtc_ctx *state)
{
/* stop as soon as possible RTC counters */
SH7305_RTC.RCR2.START = 0;
SH7305_RTC.RCR1.CF = state->rtc.RCR1.CF;
SH7305_RTC.RCR1.CIE = state->rtc.RCR1.CIE;
SH7305_RTC.RCR1.AIE = state->rtc.RCR1.AIE;
SH7305_RTC.RCR1.AF = state->rtc.RCR1.AF;
SH7305_RTC.RCR2.PEF = state->rtc.RCR2.PEF;
SH7305_RTC.RCR2.PES = state->rtc.RCR2.PES;
SH7305_RTC.RCR2.ADJ = state->rtc.RCR2.ADJ;
SH7305_RTC.RCR3.BEN = state->rtc.RCR3.BEN;
SH7305_RTC.RCR2.START = state->rtc.RCR2.START;
}
//---
// User API
//---
/* int8(), int16(): Convert BCD to integer */
static int int8(uint8_t bcd)
{
return (bcd & 0x0f) + 10 * (bcd >> 4);
}
static int int16(uint16_t bcd)
{
return (bcd & 0xf) + 10 * ((bcd >> 4) & 0xf) + 100 * ((bcd >> 8) & 0xf)
+ 1000 * (bcd >> 12);
}
/* bcd8(), bcd16(): Convert integer to BCD */
static uint8_t bcd8(int integer)
{
integer %= 100;
return ((integer / 10) << 4) | (integer % 10);
}
static uint16_t bcd16(int integer)
{
integer %= 10000;
return (bcd8(integer / 100) << 8) | bcd8(integer % 100);
}
/* sh7305_rtc_get_time(): Read the current time from the RTC */
int sh7305_rtc_get_time(rtc_time_t *time)
{
do {
SH7305_RTC.RCR1.CF = 0;
time->ticks = SH7305_RTC.R64CNT;
time->seconds = int8(SH7305_RTC.RSECCNT.byte);
time->minutes = int8(SH7305_RTC.RMINCNT.byte);
time->hours = int8(SH7305_RTC.RHRCNT.byte);
time->month_day = int8(SH7305_RTC.RDAYCNT.byte);
time->month = int8(SH7305_RTC.RMONCNT.byte);
time->year = int16(SH7305_RTC.RYRCNT.word);
time->week_day = SH7305_RTC.RWKCNT;
} while(SH7305_RTC.RCR1.CF != 0);
return 0;
}
/* sh7305_rtc_set_time(): Set current time in the RTC */
int sh7305_rtc_set_time(rtc_time_t const *time)
{
int wday = time->week_day;
if(wday >= 7) wday = 0;
do {
SH7305_RTC.RCR1.CF = 0;
SH7305_RTC.RSECCNT.byte = bcd8(time->seconds);
SH7305_RTC.RMINCNT.byte = bcd8(time->minutes);
SH7305_RTC.RHRCNT.byte = bcd8(time->hours);
SH7305_RTC.RDAYCNT.byte = bcd8(time->month_day);
SH7305_RTC.RMONCNT.byte = bcd8(time->month);
SH7305_RTC.RYRCNT.word = bcd16(time->year);
SH7305_RTC.RWKCNT = wday;
} while(SH7305_RTC.RCR1.CF != 0);
return 0;
}
//---
// Declare driver
//---
struct vhex_driver drv_rtc = {
.name = "RTC",
.hsave = (void*)&__rtc_hsave,
.hrestore = (void*)&__rtc_hrestore,
.configure = (void*)&__rtc_configure,
.state_size = sizeof(struct rtc_ctx),
.flags = {
.RTC = 1,
.SHARED = 0,
.UNUSED = 0,
},
.module_data = &(struct rtc_drv_interface){
.rtc_get_time = &sh7305_rtc_get_time,
.rtc_set_time = &sh7305_rtc_set_time,
}
};
VHEX_DECLARE_DRIVER(06, drv_rtc);

View File

@ -381,27 +381,29 @@ int sh7305_tmu_prof_init(timer_prof_t *prof)
/* sh7305_tmu_prof_enter(): Start counting time for a function */
void sh7305_tmu_prof_enter(timer_prof_t *prof)
{
prof->elapsed += *tmu_prof_tcnt;
if (tmu_prof_tcnt != NULL)
prof->elapsed += *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */
void sh7305_tmu_prof_enter_rec(timer_prof_t *prof)
{
if (!prof->rec++)
if (!prof->rec++ && tmu_prof_tcnt != NULL)
prof->elapsed += *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */
void sh7305_tmu_prof_leave_rec(timer_prof_t *prof)
{
if (!--prof->rec)
if (!--prof->rec && tmu_prof_tcnt != NULL)
prof->elapsed -= *tmu_prof_tcnt;
}
/* sh7305_tmu_prof_leave(): Stop counting time for a function */
void sh7305_tmu_prof_leave(timer_prof_t *prof)
{
prof->elapsed -= *tmu_prof_tcnt;
if (tmu_prof_tcnt != NULL)
prof->elapsed -= *tmu_prof_tcnt;
}

View File

@ -7,6 +7,8 @@
// R61524 driver API
//---
uint32_t vhex_vram[396*(224/2)];
/* r61524_frame_start() - prepar the screen and reset surfaces */
VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
{
@ -30,18 +32,24 @@ VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
r61524_select(write_data);
/* initialize surface information */
surface->vram = (void*)0xe5017000;
// surface->vram = (void*)0xe5017000;
// surface->width = 396;
// surface->height = 10;
surface->vram = (void*)vhex_vram;
surface->width = 396;
surface->height = 10;
surface->height = 224;
surface->x1 = 0;
surface->y1 = 0;
surface->x2 = 395;
surface->y2 = 9;
surface->y2 = 223;
return (0);
}
VALIGNED(4) int r61524_frame_frag_next(dsurface_t *surface)
{
(void)surface;
return -1;
#if 0
surface->y1 += 10;
if (surface->y1 >= 224) {
surface->y1 -= 10;
@ -52,10 +60,16 @@ VALIGNED(4) int r61524_frame_frag_next(dsurface_t *surface)
surface->height = 4;
surface->y2 += surface->height;
return (0);
#endif
}
VALIGNED(4) VWEAK int r61524_frame_frag_send(dsurface_t *surface)
{
uint16_t *vram = surface->vram;
for (int i = 0; i < 396*224; ++i) {
r61524_write(vram[i]);
}
#if 0
uint16_t * restrict yram = surface->vram;
int size = (surface->y1 == 220) ? 1584 : 3960;
@ -63,6 +77,7 @@ VALIGNED(4) VWEAK int r61524_frame_frag_send(dsurface_t *surface)
r61524_write(yram[i]);
}
return (0);
#endif
}
VALIGNED(4) int r61524_frame_end(dsurface_t *surface)

42
src/fs/_table.c Normal file
View File

@ -0,0 +1,42 @@
#if 0
#include <vhex/fs.h>
#include <errno.h>
/* fs_table_reserve() : reserve file descriptor */
int fs_table_reserve(void **data)
{
*data = NULL;
for (int i = 3 ; i < VHEX_NB_FILE; ++i) {
if (fs_info.table[i] == NULL) {
fs_info.table[i] = (void*)0xdeadbeef;
*data = &fs_info.table[i];
return 0;
}
}
return ENFILE;
}
/* fs_table_find() : find device-specific data */
int fs_table_find(void **data, int fd)
{
*data = NULL;
if (fd < 0 || fd >= VHEX_NB_FILE)
return EBADF;
if (fs_info.table[fd] == NULL)
return EBADF;
*data = fs_info.table[fd];
return 0;
}
/* fs_table_remove() : remove file descriptor */
int fs_table_remove(int fd)
{
if (fd < 0 || fd >= VHEX_NB_FILE)
return EBADF;
if (fs_info.table[fd] == NULL)
return EBADF;
fs_info.table[fd] = NULL;
return 0;
}
#endif

32
src/fs/close.c Normal file
View File

@ -0,0 +1,32 @@
#include <vhex/fs.h>
#include <errno.h>
int close(int fd)
{
(void)fd;
#if 0
void *data;
errno = fs_table_find(&data, fd);
if (errno != 0)
return -1;
if (fd >= 0 && fd <= 2) {
//TODO:support keyboard
//TODO:support display
errno = ENODEV;
return -1;
}
if (fs_info.fs.primitives.write == NULL) {
errno = EIO;
return -1;
}
errno = fs_info.fs.primitives.close(data);
if (errno != 0)
return -1;
return fs_table_remove(fd);
#endif
}

View File

@ -1,28 +1,46 @@
#include <unistd.h>
#include <vhex/defs/types.h>
#if 0
#include <vhex/fs.h>
#include <vhex/module.h>
#include <vhex/device.h>
ssize_t write(int fd, const void *buf, size_t size)
#include <string.h>
/* module init */
/* internal file system information */
struct __fs_info fs_info;
/* __fs_init() : initialize the fs module */
static void __fs_init(void)
{
(void)fd;
(void)buf;
(void)size;
struct vhex_device *device = vhex_device_table();
for (int i = 0; i < vhex_device_count(); ++i) {
if (device[i].flags.FS) {
memcpy(
&fs_info.fs,
&device[i],
sizeof(struct vhex_device)
);
break;
}
}
//TODO: initialise STDIN_FILENO
//TODO: initialise STDOUT_FILENO
//TODO: initialise STDERR_FILENO
}
ssize_t read(int fd, void *buf, size_t size)
/* __display_quit() : uninit the fs module */
static void __fs_quit(void)
{
(void)fd;
(void)buf;
(void)size;
//Nothing to do
}
off_t lseek(int fd, off_t offset, int whence)
{
(void)fd;
(void)offset;
(void)whence;
}
/* declare the fs module */
int close(int fd)
{
(void)fd;
}
struct vhex_module mod_fs = {
.name = "fs",
.init = &__fs_init,
.quit = &__fs_quit,
};
VHEX_DECLARE_MODULE(03, mod_fs);
#endif

6
src/fs/fugue/close.c Normal file
View File

@ -0,0 +1,6 @@
#include <vhex/fs/fugue.h>
int fugue_close(void *data)
{
(void)data;
}

23
src/fs/fugue/fugue.c Normal file
View File

@ -0,0 +1,23 @@
#if 0
#include <vhex/device.h>
#include <vhex/fs/fugue.h>
/* declare device */
struct vhex_device dev_fugue = {
.name = "Fugue",
.flags = {
.FS = 1
},
.primitives = {
.init = NULL,
.open = &fugue_open,
.write = &fugue_write,
.read = &fugue_read,
.lseek = &fugue_lseek,
.close = &fugue_close,
.quit = NULL
}
};
VHEX_DECLARE_DEVICE(dev_fugue);
#endif

8
src/fs/fugue/lseek.c Normal file
View File

@ -0,0 +1,8 @@
#include <vhex/fs/fugue.h>
off_t fugue_lseek(void *data, off_t offset, int whence)
{
(void)data;
(void)offset;
(void)whence;
}

146
src/fs/fugue/open.c Normal file
View File

@ -0,0 +1,146 @@
#if 0
#include <vhex/fs/fugue.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* fugue_open() : try to open file */
int fugue_open(void **data, const char *pathname, int flags, int mode)
{
(void)mode;
if (data == NULL || pathname == NULL) {
errno = EFAULT;
return -1;
}
/* we need to convert the pathname into FONTCHARACTER format with meta
information inside (mainly the device) */
uint16_t *fcpath = fs_path_normalize_fc(pathname);
if (fcpath == NULL) {
errno = ENOMEM;
return -1;
}
/* handle open mode */
int bfile_mode = BFile_ReadOnly;
if(flags & O_WRONLY)
bfile_mode = BFile_WriteOnly;
else if(flags & O_RDWR)
bfile_mode = BFile_ReadWrite;
/* Exclusive open means no sense unless creation is also requested */
bool excl = (flags & O_EXCL) && (flags & O_CREAT);
/* Truncation requires the file to be removed/recreated */
bool trunc = (flags & O_TRUNC) && (flags & O_CREAT);
/* Stat the entry. A special case is needed for the root, which doesn't
respond well. fs_path_normalize_fc() normalizes the path so we just
have to check for the fixed string "\\fls0\". */
bool exists;
if(!memcmp(fcpath, u"\\\\fls0\\", 16)) {
exists = true;
type = BFile_Type_Directory;
} else {
exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
if(!exists) type = -1;
}
/* If the entry exists and O_EXCL was requested, fail. */
if(exists && excl) {
errno = EEXIST;
rc = -1;
goto end;
}
/* If the entry is not a directory but O_DIRECTORY is set, fail. If the
directory doesn't exist, we fail regardless of O_CREAT. */
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
errno = (exists ? ENOTDIR : ENOENT);
rc = -1;
goto end;
}
/* If the entry is a directory, open it as such */
if(type == BFile_Type_Directory) {
void *dp = fugue_dir_explore(path);
fugue_descriptor_t data = {
.type = &fugue_dir_descriptor_type,
.data = dp,
};
fd = fugue_create_descriptor(&data);
rc = fd;
goto end;
}
/* Try and open the file normally, unless O_TRUNC is specified without
O_EXCL, in which case we simply delete and recreate the file. */
fugue_fd = BFile_EntryNotFound;
if(trunc == 0)
fugue_fd = BFile_Open(fcpath, bfile_mode);
/* If O_TRUNC is requested and either the file exists or we can create
it, remove it. (If fugue_fd < 0 an opening error might still have
occurred so we delete it just in case.) */
if((flags & O_TRUNC) && (fugue_fd >= 0 || (flags & O_CREAT))) {
if(fugue_fd >= 0)
BFile_Close(fugue_fd);
BFile_Remove(fcpath);
fugue_fd = BFile_EntryNotFound;
}
/* If the file does not exist and O_CREAT is set, create it */
if((flags & O_CREAT) && ((flags & O_TRUNC) || fugue_fd < 0)) {
new_file_size = 0;
err = BFile_Create(fcpath, BFile_File, &new_file_size);
if(err < 0) {
errno = bfile_error_to_errno(err);
rc = -1;
goto end;
}
fugue_fd = BFile_Open(fcpath, bfile_mode);
}
/* check error during hadling */
if(fugue_fd < 0) {
errno = bfile_error_to_errno(fugue_fd);
rc = fugue_fd;
goto end;
}
/* If O_APPEND is set, move to the end of the file */
// TODO: O_APPEND should move the cursor before *each* write
int pos = 0;
if((flags & O_APPEND)) {
pos = BFile_Size(fugue_fd);
BFile_Seek(fugue_fd, pos);
}
/* Return the now-open file descriptor */
fugue_fd_t *data = malloc(sizeof(fugue_fs_t));
if(data == NULL) {
BFile_Close(fugue_fd);
goto end;
}
data->fd = fugue_fd;
data->pos = pos;
/* generate file descriptor information */
fugue_descriptor_t fd_data = {
.type = &fugue_descriptor_type,
.data = data,
};
rc = fd = fugue_create_descriptor(&fd_data);
if(fd == -1) {
BFile_Close(fugue_fd);
free(data);
errno = ENFILE;
goto end;
}
end:
free(fcpath);
return rc;
}
#endif

8
src/fs/fugue/read.c Normal file
View File

@ -0,0 +1,8 @@
#include <vhex/fs/fugue.h>
ssize_t fugue_write(void *data, const void *buf, size_t size)
{
(void)data;
(void)buf;
(void)size;
}

8
src/fs/fugue/write.c Normal file
View File

@ -0,0 +1,8 @@
#include <vhex/fs/fugue.h>
ssize_t fugue_read(void *data, void *buf, size_t size)
{
(void)data;
(void)buf;
(void)size;
}

30
src/fs/lseek.c Normal file
View File

@ -0,0 +1,30 @@
#include <vhex/fs.h>
#include <errno.h>
off_t lseek(int fd, off_t offset, int whence)
{
(void)fd;
(void)offset;
(void)whence;
#if 0
void *data;
errno = fs_table_find(&data, fd);
if (errno != 0)
return -1;
if (fd >= 0 && fd <= 2) {
//TODO:support keyboard
//TODO:support display
errno = ENODEV;
return -1;
}
if (fs_info.fs.primitives.lseek == NULL) {
errno = EIO;
return -1;
}
return fs_info.fs.primitives.lseek(data, offset, whence);
#endif
}

36
src/fs/open.c Normal file
View File

@ -0,0 +1,36 @@
#include <vhex/fs.h>
#include <errno.h>
#include <stdarg.h>
/* open() : try to open file */
int open(const char *pathname, int flags, ...)
{
(void)pathname;
(void)flags;
#if 0
va_list ap;
void *data;
int mode;
va_start(ap, flags);
mode = va_arg(ap, int);
va_end(ap);
if (fs_info.fs.primitives.open == NULL) {
errno = ENOMEDIUM;
return -1;
}
errno = fs_table_reserve(&data);
if (errno != 0)
return -1;
return fs_info.fs.primitives.open(
data,
pathname,
flags,
mode
);
#endif
}

31
src/fs/read.c Normal file
View File

@ -0,0 +1,31 @@
#include <vhex/fs.h>
#include <errno.h>
ssize_t read(int fd, void *buf, size_t size)
{
(void)fd;
(void)buf;
(void)size;
return -1;
#if 0
void *data;
errno = fs_table_find(&data, fd);
if (errno != 0)
return -1;
if (fd >= 0 && fd <= 2) {
//TODO:support keyboard
//TODO:support display
errno = ENODEV;
return -1;
}
if (fs_info.fs.primitives.read == NULL) {
errno = EIO;
return -1;
}
return fs_info.fs.primitives.read(data, buf, size);
#endif
}

31
src/fs/write.c Normal file
View File

@ -0,0 +1,31 @@
#include <vhex/fs.h>
#include <errno.h>
ssize_t write(int fd, const void *buf, size_t size)
{
(void)fd;
(void)buf;
(void)size;
return -1;
#if 0
void *data;
errno = fs_table_find(&data, fd);
if (errno != 0)
return -1;
if (fd >= 0 && fd <= 2) {
//TODO:support keyboard
//TODO:support display
errno = ENODEV;
return -1;
}
if (fs_info.fs.primitives.write == NULL) {
errno = EIO;
return -1;
}
return fs_info.fs.primitives.write(data, buf, size);
#endif
}

68
src/rtc/rtc.c Normal file
View File

@ -0,0 +1,68 @@
#include <vhex/rtc/interface.h>
#include <vhex/rtc.h>
#include <vhex/module.h>
#include <vhex/driver.h>
#include <string.h>
/* internal timer information */
struct {
struct rtc_drv_interface driver;
} rtc_info;
//---
// user-level timer API
//---
/* rtc_get_time(): Read the current time from the RTC */
int rtc_get_time(rtc_time_t *time)
{
if (rtc_info.driver.rtc_get_time != NULL)
return rtc_info.driver.rtc_get_time(time);
return -1;
}
/* rtc_set_time(): Set current time in the RTC */
int rtc_set_time(rtc_time_t const *time)
{
if (rtc_info.driver.rtc_set_time != NULL)
return rtc_info.driver.rtc_set_time(time);
return -1;
}
//---
// Kernel module information
//---
/* __rtc_init() : initialize the RTC module */
static void __rtc_init(void)
{
memset(&rtc_info, 0x00, sizeof(rtc_info));
struct vhex_driver *driver = vhex_driver_table();
for (int i = 0; i < vhex_driver_count(); ++i) {
if (driver[i].flags.RTC) {
memcpy(
&rtc_info.driver,
driver[i].module_data,
sizeof(struct rtc_drv_interface)
);
break;
}
}
}
/* __rtc_quit() : uninitialize the RTC module */
static void __rtc_quit(void)
{
;
}
/* declare the timer module */
struct vhex_module mod_rtc = {
.name = "RTC",
.init = &__rtc_init,
.quit = &__rtc_quit,
};
VHEX_DECLARE_MODULE(06, mod_rtc);