Compare commits

...

18 Commits
master ... dev

Author SHA1 Message Date
Lephe a28aa9a20a
add build support for incoming fxSDK 2
Adds an fxsdk.make file that describes rules for default builds of the
library. This is compatible with custom builds (by disabling the
configure step in fxSDK 2) and mostly useful as a fast installer.
2020-12-30 18:43:47 +01:00
Lephe 7a68070bac
show version in header for static version resolution
This change moves the gint version declaration from a symbol in a
compile-time generated object file to a preprocessed header installed in
the library tree.

This makes it possible to determine the gint version statically from the
headers, which is much more robust in complex build systems that use
version information such as CMake's find_package().
2020-12-30 18:35:06 +01:00
Lephe ad6c108dfc
kernel: always pull the INTC driver
Some very trivial applications might not require its symbols explicitly,
thus the need to force a dependency (otherwise OS interrupts such as the
KEYSC are not disabled and crash the handler very quickly).
2020-10-28 10:01:55 +01:00
Lephe 2c2d1513f9
spu: more complete initialization 2020-10-24 17:40:05 +02:00
Lephe 3694f20d56
spu: starter driver, supporting direct CPU access to SPU memory 2020-10-21 18:29:04 +02:00
Lephe 8ff7d89d33
cpg, tmu: add spin waiting and spin delay functions for drivers
This change adds a new TMU function timer_spinwait() which waits for a
timer to raise its UNF flag. This makes it possible to wait even when
interrupts are disabled.

This is used by the new CPG function sleep_us_spin() which waits for a
given delay without using interrupts. This is currently used in SPU
initialization.
2020-10-21 14:49:34 +02:00
Lephe 858ec8aa12
cpg, power: improve peripheral register descriptions
The POWER and CPG modules have been reverse-engineered by Yatis.
2020-10-21 14:48:04 +02:00
Lephe 19951ccf62
mmu: add MMU registers with a driver context for PASCR and IRMCR 2020-10-21 14:44:47 +02:00
Lephe 3a15340335
topti: improve text positioning
* Specify a line height for the default fx-CG 50 font so that the height
  returned by dsize() is correctly 9, not 11.
* Adjust vertical and horizontal alignment in dtext_opt() and
  dprint_opt() by a full pixel (DTEXT_BOTTOM, DTEXT_RIGHT) and half a
  pixel (DTEXT_MIDDLE, DTEXT_CENTER) to make sure that the specified
  position is within rendered text (as in DTEXT_LEFT and TEXT_TOP) and
  to improve centering of strings with odd width or odd height, for
  which there is only one valid position.
2020-10-21 11:49:12 +02:00
Lephe e63ff8351b
dsp: enable integrated DSP in SR at startup 2020-10-09 18:58:43 +02:00
Lephe bc575f1599
intc: update interrupt sources in IPR registers
As per new documentation reverse-engineered from CPU73050.DLL.
https://bible.planet-casio.com/lephenixnoir/sh7305/intc/interrupt-sources.html
2020-10-09 18:03:08 +02:00
Lephe 52d95e72ed
stdlib: force rand() to return a non-negative number
Negative numbers come with tricky modulus results and are excluded from
the return values of the standard rand().
2020-10-09 09:17:48 +02:00
Lephe 078edb50b2
small cleanup 2020-10-05 16:31:37 +02:00
Lephe 240f29f9d5
topti: custom character and word spacing (#13)
This commit introduces custom character spacing with a new fxconv
parameter "char-spacing". Word spacing is also tied to the width of the
space character (0x20). This removes the need for special semantics on
the space character, but requires that its size be specified with gray
pixels for proportional fonts.

This also fixes problems with the size of spaces in dsize() not being
correlated with their size during rendering, since on fx-9860G topti
already used the glyph's with as word spacing.

Since fxconv changes but gint's Makefile does not track updates to
external tools, a full rebuild of gint is required past this commit.
2020-10-05 16:14:12 +02:00
Lephe 2e8b1020cb
display-fx: protect vertical lines against clipping out of bounds 2020-10-05 15:13:38 +02:00
Lephe 9b462deca1
kernel: preload add-in to TLB on SH3 (UNSTABLE) (#12) 2020-09-28 14:09:03 +02:00
Lephe e66b9083b4
kernel: do not copy data to on-chip memory on SH3
Avoids a crash at startup, but the application needs to be smart enough
to not use the data.
2020-09-28 14:06:29 +02:00
Lephe 744d243265
kernel: do SH3 initialization before context saves
This should be obvious and breaks ctx_save() for the RTC and TMU. Which
apparently never came up during testing.
2020-09-28 14:01:32 +02:00
34 changed files with 672 additions and 179 deletions

1
TODO
View File

@ -1,4 +1,5 @@
Extensions on existing code:
* project: add license file
* kernel: group linker script symbols in a single header file
* kernel: be consistent about *tlb_mapped_memory() in hw_detect()
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50

16
fxsdk.make Normal file
View File

@ -0,0 +1,16 @@
# fxsdk: version=1
configure:
mkdir -p build-fx && cd build-fx && ../configure --target=fx9860g
mkdir -p build-cg && cd build-cg && ../configure --target=fxcg50
build:
make all
install:
make install
uninstall:
make uninstall
.PHONY: configure build install uninstall

View File

@ -67,6 +67,11 @@ const clock_frequency_t *clock_freq(void);
function selects a timer with timer_setup() called with TIMER_ANY. */
void sleep_us(uint64_t delay_us);
/* sleep_us_spin(): Actively sleep for a fixed duration in microseconds
Like sleep_us(), but uses timer_spinwait() and does not rely on interrupts
being enabled. Useful in timer code running without interrupts. */
void sleep_us_spin(uint64_t delay_us);
/* sleep_ms(): Sleep for a fixed duration in milliseconds */
#define sleep_ms(delay_ms) sleep_us((delay_ms) * 1000ull)

19
include/gint/config.h.in Normal file
View File

@ -0,0 +1,19 @@
//---
// config - Compile-time generate configuration
//---
#ifndef GINT_CONFIG
#define GINT_CONFIG
#include <gint/defs/types.h>
/* GINT_VERSION: Latest tag and number of additional commits
"2.1.0" = Release 2.1.0
"2.1.1-5" = 5 commits after release 2.1.1 */
#define GINT_VERSION @GINT_VERSION@
/* GINT_HASH: Commit hash with 7 digits
0x03f7c0a0 = Commit 3f7c0a0 */
#define GINT_HASH @GINT_HASH@
#endif /* GINT_CONFIG */

View File

@ -189,6 +189,11 @@ typedef struct
/* Number of total glyphs */
uint32_t glyph_count;
/* Character spacing (usually 1) */
uint8_t char_spacing;
uint :24;
struct {
/* Unicode point of first character in block */
uint start :20;

View File

@ -6,15 +6,7 @@
#define GINT_GINT
#include <gint/defs/types.h>
/* GINT_VERSION - the library version number
gint is versioned from its repository commits on the master branch. The
GINT_VERSION integer contains the short commit hash with 7 digits.
For instance, 0x03f7c0a0 means commit 3f7c0a0. */
extern char GINT_VERSION;
#define GINT_VERSION ((uint32_t)&GINT_VERSION)
#include <gint/config.h>
/* gint_switch(): Switch out of gint to execute a function

View File

@ -38,6 +38,9 @@ enum {
INTC_RTC_ATI,
INTC_RTC_PRI,
INTC_RTC_CUI,
/* SPU; interrupts from the DSPs and the SPU-bound DMA */
INTC_SPU_DSP0,
INTC_SPU_DSP1,
};
//---

View File

@ -248,10 +248,10 @@ void getkey_repeat(int first, int next);
/* getkey_repeat_filter(): Set the repeat filter function
This function is called by getkey() and getkey_opt() every time a repeat
event occurs when GETKEY_REPEAT_FILTER. The function can decide whether to
keep, delay it or drop it entirely. It can also change the repeat delays
with getkey_repeat() for fully custom repeat delay curves.
The repeat filter is called by getkey() and getkey_opt() every time a repeat
event occurs when GETKEY_REP_FILTER is set. The filter can decide whether to
keep, delay or drop the event. It can also change the repeat delays with
getkey_repeat() for fully custom repeat delay curves.
The time elapsed since the last accepted repeat is passed to the filter
function; this time must be larger than the repeat time set with

View File

@ -54,7 +54,17 @@ typedef volatile struct
uint32_t :4;
uint32_t P1FC :4; /* Pphi divider 1 [*] */
);
pad(0x20);
pad(0x4);
lword_union(FSICLKCR,
uint32_t :16;
uint32_t DIVB :6; /* Division ratio for port B */
uint32_t :1;
uint32_t CLKSTP :1; /* Clock Stop */
uint32_t SRC :2; /* Clock source select */
uint32_t DIVA :6; /* Division ratio for port A */
);
pad(0x18);
lword_union(PLLCR,
uint32_t :17;
@ -65,8 +75,17 @@ typedef volatile struct
uint32_t CKOFF :1; /* CKO Output Stop */
uint32_t :1;
);
pad(0x14);
lword_union(SPUCLKCR,
uint32_t :23;
uint32_t CLKSTP :1; /* Clock Stop */
uint32_t _ :1; /* Unknown */
uint32_t :1;
uint32_t DIV :6; /* Division ratio */
);
pad(0x4);
pad(0x1c);
lword_union(SSCGCR,
uint32_t SSEN :1; /* Spread Spectrum Enable */
uint32_t :31;

View File

@ -119,6 +119,7 @@ typedef struct
// SH7305 Interrupt Controller. Refer to:
// "Renesas SH7724 User's Manual: Hardware"
// Section 13: "Interrupt Controller (INTC)"
// Also CPU73050.dll was disassembled to find out the bits.
//---
/* sh7305_intc_ipc_t - Interrupt Priority Controller
@ -131,29 +132,29 @@ typedef volatile struct
uint16_t TMU0_0 :4; /* TMU0 Channel 0 */
uint16_t TMU0_1 :4; /* TMU0 Channel 1 */
uint16_t TMU0_2 :4; /* TMU0 Channel 2 */
uint16_t IrDA :4; /* Infrared Communication */
uint16_t :4;
);
pad(2);
word_union(IPRB,
uint16_t :4;
uint16_t LCDC :4; /* LCD Controller */
uint16_t DMAC1A :4; /* Direct Memory Access Controller 1 */
uint16_t _ :4; /* Unknown (TODO) */
uint16_t _LCDC :4; /* SH7724: LCD Controller */
uint16_t _DMAC1A:4; /* SH7724: DMAC1 channels 0..3 */
uint16_t :4;
);
pad(2);
word_union(IPRC,
uint16_t TMU1_0 :4; /* TMU1 Channel 0 */
uint16_t TMU1_1 :4; /* TMU1 Channel 1 */
uint16_t TMU1_2 :4; /* TMU1 Channel 2 */
uint16_t :4;
uint16_t :4;
uint16_t :4;
uint16_t SPU :4; /* SPU's DSP0 and DSP1 */
);
pad(2);
word_union(IPRD,
uint16_t :4;
uint16_t MMCIF :4; /* MultiMedia Card Interface */
uint16_t _MMCIF :4; /* SH7724: MultiMedia Card Interface */
uint16_t :4;
uint16_t :4;
);
@ -171,12 +172,12 @@ typedef volatile struct
uint16_t KEYSC :4; /* Key Scan Interface */
uint16_t DMACOB :4; /* DMAC0 transfer/error info */
uint16_t USB0_1 :4; /* USB controller */
uint16_t CMT :4; /* Compare Match Timer */
uint16_t _CMT :4; /* SH7724: Compare Match Timer */
);
pad(2);
word_union(IPRG,
uint16_t SCIF0 :4; /* SCIF0 transfer/error info */
uint16_t _SCIF0 :4; /* SH7724: SCIF0 transfer/error info */
uint16_t ETMU1 :4; /* Extra TMU 1 */
uint16_t ETMU2 :4; /* Extra TMU 2 */
uint16_t :4;
@ -184,26 +185,26 @@ typedef volatile struct
pad(2);
word_union(IPRH,
uint16_t MSIOF0 :4; /* Clock-synchronized SCIF channel 0 */
uint16_t MSIOF1 :4; /* Clock-synchronized SCIF channel 1 */
uint16_t :4;
uint16_t :4;
uint16_t _MSIOF0:4; /* SH7724: Sync SCIF channel 0 */
uint16_t _MSIOF1:4; /* SH7724: Sync SCIF channel 1 */
uint16_t _1 :4; /* Unknown (TODO) */
uint16_t _2 :4; /* Unknown (TODO) */
);
pad(2);
word_union(IPRI,
uint16_t ETMU4 :4; /* Extra TMU 4 */
uint16_t :4;
uint16_t :4;
uint16_t _ :4; /* Unknown (TODO) */
uint16_t :4;
);
pad(2);
word_union(IPRJ,
uint16_t ETMU0 :4; /* Extra TMU 0 */
uint16_t :4;
uint16_t _ :4; /* Unknown (TODO) */
uint16_t FSI :4; /* FIFO-Buffered Serial Interface */
uint16_t SDHI1 :4; /* SD Card Host Interface channel 1 */
uint16_t _SDHI1 :4; /* SH7724: SD Card Host Interface 1 */
);
pad(2);
@ -211,14 +212,14 @@ typedef volatile struct
uint16_t RTC :4; /* Real-Time Clock */
uint16_t DMAC1B :4; /* DMAC1 transfer/error info */
uint16_t :4;
uint16_t SDHI0 :4; /* SD Card Host Interface channel 0 */
uint16_t :4;
);
pad(2);
word_union(IPRL,
uint16_t ETMU5 :4; /* Extra TMU 5 */
uint16_t _ :4; /* Unknown (TODO) */
uint16_t :4;
uint16_t TPU :4; /* Timer-Pulse Unit */
uint16_t :4;
);
pad(2);
@ -292,7 +293,7 @@ typedef struct
// Forward definitions
//---
/* Provided by core/gint.c */
/* Provided by intc/intc.c */
extern sh7705_intc_t SH7705_INTC;
extern sh7305_intc_t SH7305_INTC;

View File

@ -77,4 +77,79 @@ typedef struct
} GPACKED(4) utlb_data_t;
typedef volatile struct
{
lword_union(PTEH,
uint32_t VPN :22; /* Virtual Page Number */
uint32_t :2;
uint32_t ASID :8; /* Address Space Identifier */
);
lword_union(PTEL,
uint32_t :3;
uint32_t PPN :19; /* Phusical Page Number */
uint32_t :1;
uint32_t V :1; /* Valid */
uint32_t SZ1 :1; /* Size (bit 1) */
uint32_t PR :2; /* Protection */
uint32_t SZ0 :1; /* Size (bit 0) */
uint32_t C :1; /* Cacheable */
uint32_t D :1; /* Dirty */
uint32_t SH :1; /* Shared */
uint32_t WT :1; /* Write-through */
);
uint32_t TTB;
uint32_t TEA;
lword_union(MMUCR,
uint32_t LRUI :6; /* Least-Recently Used ITLB */
uint32_t :2;
uint32_t URB :6; /* UTLB Replace Boundary */
uint32_t :2;
uint32_t URC :6; /* UTLB Replace Counter */
uint32_t SQMD :1; /* Store Queue Mode */
uint32_t SV :1; /* Single Virtual Memory Mode */
uint32_t ME :1; /* TLB Extended Mode */
uint32_t :4;
uint32_t TI :1; /* TLB Invalidate */
uint32_t :1;
uint32_t AT :1; /* Address Translation */
);
pad(0x20);
lword_union(PTEA,
uint32_t :18;
uint32_t EPR :6;
uint32_t ESZ :4;
uint32_t :4;
);
pad(0x38);
lword_union(PASCR,
uint32_t :24;
uint32_t UBC :1; /* Control register area */
uint32_t UB6 :1; /* Area 6 */
uint32_t UB5 :1; /* Area 5 */
uint32_t UB4 :1; /* Area 4 */
uint32_t UB3 :1; /* Area 3 */
uint32_t UB2 :1; /* Area 2 */
uint32_t UB1 :1; /* Area 1 */
uint32_t UB0 :1; /* Area 0 */
);
pad(4);
lword_union(IRMCR,
uint32_t :27;
uint32_t R2 :1; /* Re-fetch after Register 2 change */
uint32_t R1 :1; /* Re-fetch after Register 1 change */
uint32_t LT :1; /* Re-fetch after LDTLB */
uint32_t MT :1; /* Re-fetch after writing TLB */
uint32_t MC :1; /* Re-fetch after writing insn cache */
);
} GPACKED(4) sh7305_mmu_t;
#define SH7305_MMU (*(sh7305_mmu_t *)0xff000000)
#endif /* GINT_MPU_MMU */

View File

@ -37,8 +37,8 @@ typedef volatile struct
uint32_t RS :1;
uint32_t IL :1;
uint32_t SndCache :1;
uint32_t _unknown1 :1;
uint32_t :1;
uint32_t FPU :1;
uint32_t :1;
uint32_t INTC :1;
@ -53,41 +53,44 @@ typedef volatile struct
uint32_t CMT :1;
uint32_t RWDT :1;
uint32_t DMAC1 :1;
uint32_t :1;
uint32_t TMU1 :1;
uint32_t SCIF0 :1;
uint32_t SCIF1 :1;
uint32_t :4;
uint32_t SCIF2 :1;
uint32_t SCIF3 :1;
uint32_t SCIF4 :1;
uint32_t SCIF5 :1;
uint32_t :1;
uint32_t SCIF :1;
uint32_t KEYSC :1;
uint32_t RTC :1;
uint32_t :2;
uint32_t MSIOF0 :1;
uint32_t MSIOF1 :1;
uint32_t :1;
);
/* Module Stop Control Register 1 */
lword_union(MSTPCR1,
uint32_t :19;
uint32_t KEYSC :1;
uint32_t RTC :1;
uint32_t :1;
uint32_t I2C0 :1;
uint32_t I2C1 :1;
uint32_t :8;
);
/* Module Stop Control Register 2
I stripped down this one to remove any fancy modules from the SH7724
that are unlikely to even be present in the SH7305. */
The list was established by Yatis. See <https://bible.planet-casio.
com/yatis/hardware/sh7305/power.html>. */
lword_union(MSTPCR2,
uint32_t :2;
uint32_t MMC :1;
uint32_t :1;
uint32_t ADC :1;
uint32_t :6;
uint32_t TPU :1;
uint32_t :4;
uint32_t USB0 :1;
uint32_t :20;
uint32_t :2;
uint32_t SDC :1;
uint32_t :2;
uint32_t FLCTL :1;
uint32_t ECC :1;
uint32_t :1;
uint32_t I2C :1;
uint32_t :1;
uint32_t FSI_SPU :1;
uint32_t _unknown2 :1;
uint32_t :1;
uint32_t LCDC :1;
uint32_t _unknown3 :1;
uint32_t Cmod :1;
uint32_t :1;
uint32_t Cmod2A :1;
uint32_t :2;
);
pad(4);

97
include/gint/mpu/spu.h Normal file
View File

@ -0,0 +1,97 @@
//---
// gint:mpu:spu - Sound Processing Unit and its DSPs
//---
#ifndef GINT_MPU_SPU
#define GINT_MPU_SPU
#include <gint/defs/types.h>
typedef volatile struct
{
uint32_t PBANKC0; /* Program Bank Control 0 */
uint32_t PBANKC1; /* Program Bank Control 1 */
pad(0x8);
uint32_t XBANKC0; /* X Bank Control 0 */
uint32_t XBANKC1; /* X Bank Control 1 */
pad(0x10);
lword_union(SPUSRST, /* SPU Software Reset */
uint32_t :24;
uint32_t DB3 :1; /* DMABUF 3 */
uint32_t DB2 :1; /* DMABUF 2 */
uint32_t DB1 :1; /* DMABUF 1 */
uint32_t DB0 :1; /* DMABUF 0 */
uint32_t :3;
uint32_t RST :1; /* Reset */
);
uint32_t const SPUADR; /* SPU address */
uint32_t const ENDIAN; /* SuperHyway endian */
pad(0x10);
uint32_t GCOM[8]; /* Global Common */
pad(0x20);
uint32_t const DMABUF[4]; /* Inter-DSP Communication Buffer */
} GPACKED(4) spu_t;
typedef volatile struct
{
uint32_t SBAR; /* Source base address */
uint32_t SAR; /* Source address */
uint32_t DBAR; /* Destination base address */
uint32_t DAR; /* Destination address */
uint32_t TCR; /* Transfer count */
uint32_t SHPRI; /* SHway priority */
uint32_t CHCR; /* Channel control */
pad(0x4);
} GPACKED(4) spu_dsp_dma_t;
typedef volatile struct {
uint32_t LSA; /* Loop start address */
uint32_t LEA; /* Loop end address */
pad(0x8);
} GPACKED(4) spu_dsp_loop_t;
typedef volatile struct
{
uint32_t DSPRST; /* DSP full reset */
uint32_t DSPCORERST; /* DSP core reset */
uint32_t const DSPHOLD; /* DSP hold */
uint32_t DSPRESTART; /* DSP restart */
pad(0x8);
uint32_t IEMASKC; /* CPU interrupt source mask */
uint32_t IMASKC; /* CPU interrupt signal mask */
uint32_t IEVENTC; /* CPU interrupt source */
uint32_t IEMASKD; /* DSP interrupt source mask */
uint32_t IMASKD; /* DSP interrupt signal mask */
uint32_t IESETD; /* DSP interrupt set */
uint32_t IECLRD; /* DSP interrupt clear */
uint32_t OR; /* DMAC operation */
uint32_t COM[8]; /* CPU-DSP communication */
uint32_t BTADRU; /* Bus-through address high */
uint32_t BTADRL; /* Bus-through address low */
uint32_t WDATU; /* Bus-through write data high */
uint32_t WDATL; /* Bus-through write data low */
uint32_t RDATU; /* Bus-through read data high */
uint32_t RDATL; /* Bus-through read data low */
uint32_t BTCTRL; /* Bus-through mode control */
uint32_t SPUSTS; /* SPU status */
pad(0x88);
spu_dsp_dma_t DMA[3];
pad(0x20);
spu_dsp_loop_t LP[3];
} GPACKED(4) spu_dsp_t;
#define SH7305_SPU (*(spu_t *)0xfe2ffc00)
#define SH7305_DSP0 (*(spu_dsp_t *)0xfe2ffd00)
#define SH7305_DSP1 (*(spu_dsp_t *)0xfe3ffd00)
#endif /* GINT_MPU_SPU */

View File

@ -19,10 +19,12 @@ void *calloc(size_t nmemb, size_t size);
/* realloc(): Reallocate dynamic memory */
void *realloc(void *ptr, size_t size);
#define RAND_MAX 0x7fffffff
/* srand(): Seed the PRNG */
void srand(unsigned int seed);
/* rand(): Generate a pseudo-random number */
/* rand(): Generate a pseudo-random number between 0 and RAND_MAX */
int rand(void);
#endif /* GINT_STD_STDLIB */

View File

@ -41,7 +41,7 @@
* Set a specific ID in timer_setup(), in which case the delay is no longer
interpreter as count of µs, but as a TCOR value.
* If this ID is a TMU, you can further add (with + or |) a prescaler
specification, one of TIMER_Po_{4,16,64,256}.
specification, one of TIMER_Pphi_{4,16,64,256}.
* Regardless of how the timer was obtained, you can use timer_reload() to
replace the value of TCOR.
* Also note that TMU0, TMU1, TMU2 and the ETMU have respective interrupt
@ -59,7 +59,7 @@
Standard TMU can count at different speeds. A fast speed offers more
precision but a slower speed offers longer delays. gint automatically
selects suitable speed by default.
selects suitable speeds by default.
If you want something very particular, you can add (with + or |) a prescaler
value to a chosen ID in timer_setup() to request that specific value. The
@ -186,6 +186,12 @@ void timer_stop(int timer);
it may have only paused. If the timer never stops, you're in trouble. */
void timer_wait(int timer);
/* timer_spinwait(): Actively wait for a timer to raise UNF
Waits until the timer raises UNF, without sleeping. This is useful for
delays in driver code that is run when interrupts are disabled. This relies
neither on the interrupt signal nor on the UNIE flag. */
void timer_spinwait(int timer);
//---
// Low-level functions
//---

View File

@ -26,7 +26,7 @@ machine ?= -m4-nofpu -mb
endif
# Compiler flags, assembler flags, dependency generation, archiving
inc := -I ../include
inc := -I ../include -I include
cflags := $(machine) -ffreestanding -nostdlib -Wall -Wextra -std=c11 -Os \
-fstrict-volatile-bitfields $(inc) $(CONFIG.MACROS) \
$(CONFIG.CFLAGS)
@ -64,7 +64,7 @@ src_obj := $(foreach s,$(src),$(call src2obj,$s))
# Files with special handling
spe-fx := ../src/font5x7.png
spe-cg := ../src/font8x9.png
spe_obj := version.o $(foreach s,$(spe-$(CONFIG.TARGET)),$(call src2obj,$s))
spe_obj := $(foreach s,$(spe-$(CONFIG.TARGET)),$(call src2obj,$s))
# All object files
obj := $(src_obj) $(spe_obj)
@ -87,6 +87,8 @@ objcopy = $(CONFIG.TOOLCHAIN)-objcopy
# Version symbol is obtained by using the last commit hash on 7 nibbles
version_hash = 0x0$(shell git rev-parse --short HEAD)
# Version number: closest tag, with additional commits
version_number = $(shell git describe --tag --always | cut -d- -f1-2)
#
@ -95,7 +97,7 @@ version_hash = 0x0$(shell git rev-parse --short HEAD)
all: $(target)
$(target): $(obj)
$(target): include/gint/config.h $(obj)
@ rm -f $@
$(call cmd_l,ar,$@) $(ar) rcs $(arflags) $@ $^
@ -113,6 +115,11 @@ src/%.c.o: ../src/%.c src/%.c.d
$(call cmd_b,gcc,$*.c) $(gcc) -c $< -o $@ $(dflags) $(cflags)
# Special files
include/gint/config.h: ../include/gint/config.h.in $(gitfile)
@ mkdir -p $(dir $@)
$(call cmd_m,sed,$@) cp $< $@
@ sed -i'' 's/@GINT_VERSION@/"$(version_number)"/' $@
@ sed -i'' 's/@GINT_HASH@/$(version_hash)/' $@
$(call src2obj,../src/font5x7.png): ../src/font5x7.png
@ mkdir -p $(dir $@)
$(call cmd_m,fxconv,font5x7.png) fxconv -f $< -o $@ \
@ -123,21 +130,14 @@ $(call src2obj,../src/font8x9.png): ../src/font8x9.png
$(call cmd_m,fxconv,font8x9.png) fxconv -f $< -o $@ \
--cg --toolchain=$(CONFIG.TOOLCHAIN) name:gint_font8x9 \
charset:print grid.size:8x11 grid.padding:1 grid.border:0 \
proportional:true
# Version symbol. ld generates a .stack section for unknown reasons; I remove
# it in the linker script.
version.o: $(gitfile)
@ mkdir -p $(dir $@)
@ echo "_GINT_VERSION = $(version_hash);" > $@.txt
$(call cmd_b,ld,$@) $(ld) -r -R $@.txt -o $@
proportional:true height:9
#
# Cleaning
#
clean:
@ rm -rf src version.o{,txt}
@ rm -rf src include
distclean: clean
@ rm -rf Makefile $(CONFIG) $(target)
@ -156,7 +156,9 @@ install: $(target)
install -d $(PREFIX)
install $(target) $(m644) $(PREFIX)
install ../$(CONFIG.TARGET.LONG).ld $(m644) $(PREFIX)
cp -r ../include/gint $(PREFIX)/include
install -d $(PREFIX)/include/gint
cp ../include/gint/*.h $(PREFIX)/include/gint/
cp include/gint/*.h $(PREFIX)/include/gint/
uninstall:
rm -f $(PREFIX)/$(target)

View File

@ -56,7 +56,9 @@ static void sh7705_probe(void)
/* Deduce the frequency of the main clocks. This value is ckio/3 */
int ckio_3 = 9830400;
/* Exchange the setting values 2 and 3 */
/* Exchange the setting values 2 and 3 (corresponding to /3 and /4)
This means that /1, /2, /4 are now 0, 1, 2, which is perfect for a
quick bit shift */
idiv = idiv ^ (idiv >> 1);
pdiv = pdiv ^ (pdiv >> 1);
@ -87,8 +89,8 @@ static void sh7305_probe(void)
if(CPG.FLLFRQ.SELXM == 1) fll >>= 1;
freq.FLL = fll;
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but
SH7305 behaves as 1 / (2^setting + 1). */
/* On SH7724, the divider ratio is given by 1 / (setting + 1), but on
the SH7305 it is 1 / (2^setting + 1). */
int divb = CPG.FRQCRA.BFC;
int divi = CPG.FRQCRA.IFC;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -56,6 +56,9 @@ static struct info {
{ IPRK, 0xf000, IMR10, 0x04, IPRA, 0x000f },
{ IPRK, 0xf000, IMR10, 0x02, IPRA, 0x000f },
{ IPRK, 0xf000, IMR10, 0x01, IPRA, 0x000f },
/* SPU */
{ IPRC, 0x000f, IMR3, 0x04, _ /* Not supported on SH3! */ },
{ IPRC, 0x000f, IMR4, 0x08, _ },
};

View File

@ -36,4 +36,31 @@ void cpu_setCPUOPM(uint32_t CPUOPM);
/* cpu_getCPUOPM(): Get the CPU OperatioN Mode register */
uint32_t cpu_getCPUOPM(void);
//---
// Status Register
//---
/* Status Register bits */
typedef lword_union(sr_t,
uint32_t :1;
uint32_t MD :1;
uint32_t RB :1;
uint32_t BL :1;
uint32_t RC :12;
uint32_t :3;
uint32_t DSP :1;
uint32_t DMY :1;
uint32_t DMX :1;
uint32_t M :1;
uint32_t Q :1;
uint32_t IMASK :4;
uint32_t RF :2;
uint32_t S :1;
uint32_t T :1;
);
/* Get and set sr through the sr_t type */
sr_t cpu_getSR(void);
void cpu_setSR(sr_t sr);
#endif /* GINT_CORE_CPU */

View File

@ -5,21 +5,23 @@
.global _cpu_setVBR
.global _cpu_setCPUOPM
.global _cpu_getCPUOPM
.global _cpu_getSR
.global _cpu_setSR
/* cpu_setVBR(): Change VBR address */
.section .gint.mapped, "ax"
_cpu_setVBR_reloc:
mov.l r8, @-r15
mov.l r9, @-r15
sts.l pr, @-r15
stc.l sr, @-r15
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r1
shll2 r1
shll2 r1
mov #0xf, r9
shll2 r9
shll2 r9
stc sr, r0
or r1, r0
or r9, r0
ldc r0, sr
/* Set the new VBR address */
@ -30,10 +32,17 @@ _cpu_setVBR_reloc:
jsr @r5
mov r6, r4
/* Enable interrupts again by restoring the status register */
ldc.l @r15+, sr
lds.l @r15+, pr
/* Enable interrupts again */
stc sr, r0
not r9, r9
and r9, r0
ldc r0, sr
/* Return the previous VBR address */
mov r8, r0
lds.l @r15+, pr
mov.l @r15+, r9
rts
mov.l @r15+, r8
@ -68,5 +77,16 @@ _cpu_getCPUOPM:
mov.l @r0, r0
.align 4
1: .long 0xff2f0000
/* cpu_getSR(): Get status register */
_cpu_getSR:
stc sr, r0
rts
nop
/* cpu_setSR(): Set status register */
_cpu_setSR:
ldc r4, sr
rts
nop

View File

@ -16,12 +16,17 @@
static void kinit_cpu(void);
/* Forcefully pull in the INTC driver which gint cannot run without */
extern gint_driver_t drv_intc;
GUNUSED gint_driver_t *gint_required_intc = &drv_intc;
//---
// Context for the CPU and registers not directly managed by a driver
//---
typedef struct
{
sr_t SR;
uint32_t VBR;
uint32_t CPUOPM;
} ctx_t;
@ -31,11 +36,19 @@ GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(ctx_t *ctx)
{
if(isSH4()) ctx->CPUOPM = cpu_getCPUOPM();
if(isSH4())
{
ctx->CPUOPM = cpu_getCPUOPM();
ctx->SR = cpu_getSR();
}
}
static void ctx_restore(ctx_t *ctx)
{
if(isSH4()) cpu_setCPUOPM(ctx->CPUOPM);
if(isSH4())
{
cpu_setCPUOPM(ctx->CPUOPM);
cpu_setSR(ctx->SR);
}
}
//---
@ -58,9 +71,8 @@ static void drivers_save_and_init(GUNUSED int zero)
for driver_asc(d)
{
if(d->ctx_save) d->ctx_save(d->sys_ctx);
if(isSH3() && d->driver_sh3) d->driver_sh3();
if(d->ctx_save) d->ctx_save(d->sys_ctx);
if(d->init) d->init();
}
}
@ -100,7 +112,15 @@ static void drivers_switch(int who)
static void kinit_cpu(void)
{
if(isSH4()) cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
if(isSH4())
{
cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
/* Enable DSP mode on the CPU */
sr_t SR = cpu_getSR();
SR.DSP = 1;
cpu_setSR(SR);
}
}
/* kinit(): Install and start gint */

View File

@ -113,16 +113,42 @@ int start(int isappli, int optnum)
/* Detect hardware; this will mainly tell SH3 from SH4 on fx-9860G */
hw_detect();
/* The dynamic TLB mechanism for old SH3-based fx-9860G (basically OS
1.00 and the fx-9860G emulator) is not clear yet, so gint can't load
pages dynamically. Load everything preventively (works only if the
add-in is small enough) */
#ifdef FX9860G
if(isSH3())
{
/* Try to map every ROM address up to _srom */
volatile uint8_t *x = (void *)0x00300000;
uint32_t loaded = 0;
while(loaded < (uint32_t)&srom)
{
GUNUSED volatile uint8_t y = *x;
loaded += 1024;
x += 1024;
}
}
#endif
/* Load data sections and wipe the bss section. This has to be done
first for static and global variables to be initialized */
regcpy(&ldata, &sdata, &rdata);
regcpy(&lilram, &silram, &rilram);
regcpy(&lxram, &sxram, &rxram);
regcpy(&lyram, &syram, &ryram);
regclr(&rbss, &sbss);
/* Do not load data to ILRAM, XRAM or YRAM on SH3 - the areas don't
exist. If you use them, you're responsible! */
if(!isSH3())
{
regcpy(&lilram, &silram, &rilram);
regcpy(&lxram, &sxram, &rxram);
regcpy(&lyram, &syram, &ryram);
}
#ifdef FX9860G
/* Copy permanentely-mapped code to start of user RAM (on fx-CG 50 it
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
is loaded along ILRAM contents) */
void *rgmapped = mmu_uram();
regcpy(&lgmapped, &sgmapped, rgmapped);
@ -158,6 +184,7 @@ int start(int isappli, int optnum)
}
callarray(&bdtors, &edtors);
/* Before leaving the application, we need to clean everything we
changed to hardware settings and peripheral modules. The OS is bound
to be confused (and hang, or crash, or any other kind of giving up)

View File

@ -1,8 +1,9 @@
//---
// gint:core:mmu - MMU-related definitions
// gint:mmu:mmu - MMU driver definition and context management
//---
#include <gint/mmu.h>
#include <gint/drivers.h>
#include <gint/hardware.h>
//---
@ -148,3 +149,54 @@ uint32_t utlb_translate(uint32_t page)
}
return -1;
}
//---
// Initialization
//---
static void init(void)
{
/* Make writes to the control register area synchronous; this is needed
for the SPU to operate properly */
if(isSH4()) SH7305_MMU.PASCR.UBC = 1;
}
//---
// Context management
//---
typedef struct {
uint32_t PASCR;
uint32_t IRMCR;
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
if(isSH3()) return;
ctx_t *ctx = buf;
ctx->PASCR = SH7305_MMU.PASCR.lword;
ctx->IRMCR = SH7305_MMU.IRMCR.lword;
}
static void ctx_restore(void *buf)
{
if(isSH3()) return;
ctx_t *ctx = buf;
SH7305_MMU.PASCR.lword = ctx->PASCR;
SH7305_MMU.IRMCR.lword = ctx->IRMCR;
}
gint_driver_t drv_mmu = {
.name = "MMU",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
};
GINT_DECLARE_DRIVER(1, drv_mmu);

View File

@ -61,9 +61,8 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
/* Move to top row */
uint16_t *target = gint_vram + 396 * y;
/* Character spacing and space waiting to be drawn */
int space = 1;
int active_space = 0;
/* Character spacing waiting to be drawn, in pixels */
int space = 0;
/* Read each character from the input string */
while(1)
@ -74,29 +73,23 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
int glyph = topti_glyph_index(f, code_point);
if(glyph < 0) continue;
/* Draw the space if background is opaque */
int prop_space = (code_point == ' ' && f->prop) ? 5 : 0;
if(active_space || prop_space)
{
active_space += prop_space;
if(bg >= 0) drect(x, y, x + active_space - 1,
y + height - 1, bg);
}
x += active_space;
if(prop_space) { active_space = space; continue; }
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
/* Draw character spacing if background is opaque */
if(space && bg >= 0) drect(x, y, x+space-1, y+height-1, bg);
x += space;
if(x >= 396) break;
int index = topti_offset(f, glyph);
/* Compute horizontal intersection between glyph and screen */
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
int width = dataw, left = 0;
if(x + dataw <= 0)
{
x += dataw;
active_space = space;
space = f->char_spacing;
continue;
}
if(x < 0) left = -x, width += x;
@ -108,7 +101,7 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
dataw, fg, bg);
x += dataw;
active_space = space;
space = f->char_spacing;
}
}
@ -121,10 +114,10 @@ void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
int w, h;
dsize(str, topti_font, &w, &h);
if(halign == DTEXT_RIGHT) x -= w;
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
if(valign == DTEXT_BOTTOM) y -= h;
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
if(halign == DTEXT_RIGHT) x -= w - 1;
if(halign == DTEXT_CENTER) x -= (w >> 1);
if(valign == DTEXT_BOTTOM) y -= h - 1;
if(valign == DTEXT_MIDDLE) y -= (h >> 1);
}
topti_render(x, y, str, topti_font, fg, bg);

View File

@ -291,24 +291,3 @@ int bopti_clip(bopti_image_t const *img, struct rbox *r)
/* Return non-zero if the result is empty */
return (width <= 0 || height <= 0);
}
void bopti_render_noclip(bopti_image_t const *img, struct rbox *r,
uint32_t *v1, uint32_t *v2)
{
int left = r->left;
/* Start column and end column (both included) */
r->left >>= 5;
if(r->columns == 1 && (r->visual_x & 31) + r->width <= 32)
{
r->x = (left & 31) - (r->visual_x & 31);
bopti_render_scsp(img, r, v1, v2);
}
else
{
/* x-coordinate of the first pixel of the first column */
r->x = r->visual_x - (left & 31);
bopti_render(img, r, v1, v2);
}
}

View File

@ -44,6 +44,8 @@ void gint_dvline(int y1, int y2, int x, int color)
if((uint)x >= 128) return;
if(y1 > y2) swap(y1, y2);
if(y1 >= 64 || y2 < 0) return;
if(y1 < 0) y1 = 0;
if(y2 >= 64) y2 = 63;
uint32_t *base = gint_vram + (y1 << 2) + (x >> 5);
uint32_t *lword = base + ((y2 - y1 + 1) << 2);

View File

@ -30,18 +30,24 @@ void masks(int x1, int x2, uint32_t *masks);
@rbox Rendering box */
int bopti_clip(bopti_image_t const *img, struct rbox *rbox);
/* bopti_render_noclip(): Render a bopti image without clipping
This function is only ever slightly faster than bopti_render_clip(),
eliminating two types of coordinate checks:
1. The bounding box does not overflow from the image
2. The final rendering does not overflow from the screen
/* bopti_render(): Render a bopti image
Copies an image into the VRAM. This function does not perform clipping;
use bopti_clip() on the rbox before calling it if needed.
@x @y Location of the top-left corner
@img Image encoded by [fxconv]
@left @top @w @h Bounding box to render
@v1 @v2 VRAMs (gray rendering is used if v2 != NULL) */
void bopti_render_noclip(bopti_image_t const *img, struct rbox *rbox,
uint32_t *v1, uint32_t *v2);
@img Image encoded by [fxconv]
@rbox Rendering box (may or may not be clipped)
@v1 @v2 VRAMs (gray rendering is used if v2 != NULL) */
void bopti_render(bopti_image_t const *img, struct rbox *rbox, uint32_t *v1,
uint32_t *v2);
/* bopti_render_scsp(): Single-column single-position image renderer
This function is a specialized version of bopti_render() that can be used
when only a single column of the source image is used (all pixels to be
rendered are in a single 32-aligned 32-wide pixel column of the source) and
a single position of the VRAM is used (all pixels to be rendered end up in a
single 32-aligned 32-wide pixel column of the VRAM). */
void bopti_render_scsp(bopti_image_t const *img, struct rbox *rbox,
uint32_t *v1, uint32_t *v2);
//---
// Alternate rendering modes

View File

@ -133,7 +133,7 @@ void topti_render(int x, int y, char const *str_char, font_t const *f,
free = topti_split(data+index, width, height, free, operators);
/* Potential space after the glyph */
int space = (*str != 0);
int space = (*str != 0) ? f->char_spacing : 0;
free -= space;
if(free > 0) continue;
@ -186,10 +186,10 @@ void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
int w, h;
dsize(str, topti_font, &w, &h);
if(halign == DTEXT_RIGHT) x -= w;
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
if(valign == DTEXT_BOTTOM) y -= h;
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
if(halign == DTEXT_RIGHT) x -= w - 1;
if(halign == DTEXT_CENTER) x -= (w >> 1);
if(valign == DTEXT_BOTTOM) y -= h - 1;
if(valign == DTEXT_MIDDLE) y -= (h >> 1);
}
topti_render(x, y, str, topti_font, topti_asm_text[fg],

View File

@ -3,10 +3,6 @@
#include "../render/render.h"
/* TODO: These parameters will eventually be specified by the font */
#define CHAR_SPACING 1
#define PROP_SPACING 5
/* dfont(): Set the default font for text rendering */
font_t const *dfont(font_t const * font)
{
@ -105,39 +101,34 @@ uint32_t topti_utf8_next(uint8_t const **str_pointer)
void dsize(char const *str_char, font_t const * f, int *w, int *h)
{
uint8_t const *str = (void *)str_char;
uint32_t code_point;
if(!f) f = topti_font;
if(h) *h = f->line_height;
if(!w) return;
/* Width for monospaced fonts is easy, unfortunately we still need to
compute the length of [str]. Critical applications might do the
product themselves to avoid this cost. */
compute the length and group bytes into Unicode code points. */
if(!f->prop)
{
int length = 0;
while(*str++) length++;
*w = (f->width + CHAR_SPACING) * length - CHAR_SPACING;
while((code_point = topti_utf8_next(&str))) length++;
*w = (f->width + f->char_spacing) * length - f->char_spacing;
return;
}
/* For proportional fonts, fetch the width of each individual glyphs */
int width = 0;
uint32_t code_point;
while(1)
{
code_point = topti_utf8_next(&str);
if(!code_point) break;
if(code_point == ' ')
{
width += PROP_SPACING + CHAR_SPACING;
continue;
}
int glyph = topti_glyph_index(f, code_point);
if(glyph >= 0) width += f->glyph_width[glyph] + CHAR_SPACING;
if(glyph < 0) continue;
width += f->glyph_width[glyph] + f->char_spacing;
}
*w = width - CHAR_SPACING;
*w = width - f->char_spacing;
}

98
src/spu/spu.c Normal file
View File

@ -0,0 +1,98 @@
#include <gint/mpu/spu.h>
#include <gint/mpu/cpg.h>
#include <gint/mpu/power.h>
#include <gint/drivers.h>
#include <gint/clock.h>
#include <gint/intc.h>
#define SPU SH7305_SPU
#define DSP0 SH7305_DSP0
#define DSP1 SH7305_DSP1
#define CPG SH7305_CPG
#define POWER SH7305_POWER
static void init(void)
{
/* Block SPU interrupts from DSP0, DSP1, and their DMA */
intc_priority(INTC_SPU_DSP0, 0);
intc_priority(INTC_SPU_DSP1, 0);
/* Stop both the SPU and FSI clocks */
CPG.FSICLKCR.lword = 0x00000103;
CPG.SPUCLKCR.lword = 0x00000100;
/* Enable the FSI clock, then the SPU/SPURAM clock */
CPG.FSICLKCR.CLKSTP = 0;
CPG.SPUCLKCR.CLKSTP = 0;
/* Power the clocks through MSTPCR2 */
POWER.MSTPCR2.FSI_SPU = 0;
/* Reset the SPU */
SPU.SPUSRST.RST = 0;
sleep_us_spin(1000);
SPU.SPUSRST.RST = 1;
sleep_us_spin(1000);
/* Initially give all P memory and X memory to DSP0 */
SPU.PBANKC0 = 0x1f;
SPU.PBANKC1 = 0x00;
SPU.XBANKC0 = 0x7f;
SPU.XBANKC1 = 0x00;
/* Perform full DSP resets */
DSP0.DSPCORERST = 1;
DSP1.DSPCORERST = 1;
DSP0.DSPRST = 0;
DSP1.DSPRST = 0;
sleep_us_spin(1000);
}
int spu_zero(void)
{
return 0;
}
//---
// Hardware context
//---
typedef struct
{
uint32_t PBANKC0, PBANKC1;
uint32_t XBANKC0, XBANKC1;
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
ctx->PBANKC0 = SPU.PBANKC0;
ctx->PBANKC1 = SPU.PBANKC1;
ctx->XBANKC0 = SPU.XBANKC0;
ctx->XBANKC1 = SPU.XBANKC1;
}
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
SPU.PBANKC0 = ctx->PBANKC0;
SPU.PBANKC1 = ctx->PBANKC1;
SPU.XBANKC0 = ctx->XBANKC0;
SPU.XBANKC1 = ctx->XBANKC1;
}
//---
// Driver structure definition
//---
gint_driver_t drv_spu = {
.name = "SPU",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
};
GINT_DECLARE_DRIVER(3, drv_spu);

View File

@ -10,5 +10,5 @@ void srand(unsigned int seed)
int rand(void)
{
return tinymt32_generate_uint32(&random);
return tinymt32_generate_uint32(&random) & 0x7fffffff;
}

View File

@ -5,8 +5,7 @@
#include <gint/clock.h>
#include <gint/timer.h>
/* sleep_us(): Sleep for a fixed duration in microseconds */
void sleep_us(uint64_t delay_us)
static void do_sleep(uint64_t delay_us, int spin)
{
volatile int flag = 0;
@ -14,5 +13,18 @@ void sleep_us(uint64_t delay_us)
if(timer < 0) return;
timer_start(timer);
timer_wait(timer);
if(spin) timer_spinwait(timer);
else timer_wait(timer);
}
/* sleep_us(): Sleep for a fixed duration in microseconds */
void sleep_us(uint64_t delay_us)
{
do_sleep(delay_us, 0);
}
/* sleep_us_spin(): Actively sleep for a fixed duration in microseconds */
void sleep_us_spin(uint64_t delay_us)
{
do_sleep(delay_us, 1);
}

View File

@ -261,13 +261,13 @@ void timer_stop(int id)
}
}
/* timer_wait() - wait until a timer is stopped */
/* timer_wait(): Wait for a timer to stop */
void timer_wait(int id)
{
if(id < 3)
{
tmu_t *T = &TMU[id];
/* Sleep if an interruption will wake us up */
/* Sleep only if an interrupt will be there to wake us up */
while(*TSTR & (1 << id)) if(T->TCR.UNIE) sleep();
}
else
@ -277,6 +277,21 @@ void timer_wait(int id)
}
}
/* timer_spinwait(): Actively wait for a timer to raise UNF */
void timer_spinwait(int id)
{
if(id < 3)
{
tmu_t *T = &TMU[id];
while(!T->TCR.UNF) {}
}
else
{
etmu_t *T = &ETMU[id-3];
while(!T->TCR.UNF) {}
}
}
//---
// Predefined timer callbacks
//---