dma: add a new driver to support r61524

Also add a power interface (without driving code) and switch toolchain
because the previous sh4eb-nofpu-elf toolchain was not completely
FPU-free.
This commit is contained in:
lephe 2019-03-10 15:45:34 +01:00
parent f33cb3cf80
commit 04231ea5d6
18 changed files with 578 additions and 144 deletions

View file

@ -47,8 +47,8 @@ or both. There are a few dependencies:
* A suitable GCC toolcahin in the `PATH`. You can absolutely *not* build gint
with your system compiler!
* For fx-9860G II, `sh3eb-elf` is strongly advised
* For fx-CG 50, `sh4eb-nofpu-elf` is slightly better but `sh3eb-elf` is
completely fine
* For fx-CG 50, `sh4eb-elf` (with `-m4-nofpu`) is slightly better but
`sh3eb-elf` is completely fine
* The [fxSDK](http://git.planet-casio.com/lephe/fxsdk) installed and available
in the PATH. You will need `fxsdk` and `fxconv` to build gint, and if you
intend to develop add-ins for fx-9860G II, you probably want `fxg1a` as well.
@ -83,7 +83,7 @@ with `--prefix`, or if you built your compiler as root.
### Building for fx-CG 50
Create a build directory and configure in it. The default toolchain is
`sh4eb-nofpu-elf`, if you wish to build with `sh3eb-elf`, you need to add a
`sh4eb-elf`, if you wish to build with `sh3eb-elf`, you need to add a
command-line option `--toolchain=sh3eb-elf`.
% mkdir build.cg && cd build.cg

6
configure vendored
View file

@ -45,7 +45,7 @@ Target selection:
fxcg50 covers just the fx-CG 50; there is some unofficial compatibility with
fx-CG 10/20. All of these are SH4-only.
Default toolchain is 'sh4eb-nofpu-elf'.
Default toolchain is 'sh4eb-elf'.
Build options:
--toolchain=TRIPLET Build with a different toolchain
@ -102,11 +102,13 @@ for arg; do case "$arg" in
toolchain=${toolchain:-sh3eb-elf};;
"fxcg50")
target=fxcg50
toolchain=${toolchain:-sh4eb-nofpu-elf};;
toolchain=${toolchain:-sh4eb-elf};;
*)
echo "error: invalid target '$target'"
fail=true
esac;;
--toolchain=*)
toolchain=${arg#*=};;
--prefix=*)
prefix=${arg#*=};;

69
include/gint/dma.h Normal file
View file

@ -0,0 +1,69 @@
//---
// gint:dma - Direct Memory Access for efficient data transfer
//
// Currently this module is used only to transfer data to the display on
// fxcg50, but fast memcpy() is apparently possible as well.
//---
#ifndef GINT_DMA
#define GINT_DMA
#include <gint/defs/types.h>
/* dma_size_t - Transfer block size */
typedef enum
{
/* Normal transfers of 1, 2, 4, 8, 16 or 32 bytes at a time */
DMA_1B = 0,
DMA_2B = 1,
DMA_4B = 2,
DMA_8B = 7,
DMA_16B = 3,
DMA_32B = 4,
/* Transfers of 16 or 32 bytes divided in two operations */
DMA_16B_DIV = 11,
DMA_32B_DIV = 12,
} dma_size_t;
/* dma_address_t - Addressing mode for source and destination regions */
typedef enum
{
/* Fixed address mode: the same address is read/written at each step */
DMA_FIXED = 0,
/* Increment: address is incremented by transfer size at each step */
DMA_INC = 1,
/* Decrement: only allowed for 1/2/4-byte transfers */
DMA_DEC = 2,
/* Fixed division mode: address is fixed even in 16/32-divide mode */
DMA_FIXEDDIV = 3,
} dma_address_t;
/* dma_transfer() - Start a data transfer on channel 0
This function returns just when the transfer starts. The transfer will end
later on and the DMA will be stopped by an interrupt. Call
dma_transfer_wait() if you need to wait for the transfer to finish. Don't
start a new transfer until the current one is finished!
@size Transfer size
@blocks Number of blocks (transferred memory = size * blocks)
@src Source pointer, must be aligned with transfer size
@src_mode Source address mode
@dst Destination address, must be aligned with transfer size
@dst_mode Destination address mode */
void dma_transfer(dma_size_t size, uint length,
void *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode);
/* dma_transfer_wait() - Wait for a transfer on channel 0 to finish
You should call this function when you need to transfer to be complete
before continuing execution. If you are sure that the transfer is finished,
this is not necessary (the only way to know is to look at the DMA registers
or record interrupts). */
void dma_transfer_wait(void);
#endif /* GINT_DMA */

View file

@ -1,9 +1,9 @@
//---
// gint:core:cpg - Clock Pulse Generator
// gint:mpu:cpg - Clock Pulse Generator
//---
#ifndef GINT_CORE_CPG
#define GINT_CORE_CPG
#ifndef GINT_MPU_CPG
#define GINT_MPU_CPG
#include <gint/defs/attributes.h>
#include <gint/defs/types.h>
@ -79,4 +79,4 @@ typedef volatile struct
#define SH7305_CPG (*((sh7305_cpg_t *)0xa4150000))
#endif /* GINT_CORE_CPG */
#endif /* GINT_MPU_CPG */

89
include/gint/mpu/dma.h Normal file
View file

@ -0,0 +1,89 @@
//---
// gint:mpu:dma - Direct Memory Access control
//
// The DMA is a major module on fxcg50 because it is needed to send data
// to the display at a reasonable speed. On fx9860g, it is very rarely
// used, if ever.
//---
#ifndef GINT_MPU_DMA
#define GINT_MPU_DMA
#include <gint/defs/types.h>
//---
// SH7305 Direct Memory Access Controller. Refer to:
// "Renesas SH7724 User's Manual: Hardware"
// Section 16: "Direct Memory Access Controller (DMAC)"
//---
/* sh7305_dma_channel_t - One of the main 6 channels of the DMA
Note that the many settings are only available on channels 0 to 3 (denoted
by [0..3]) or on channels 0 and 1 (denoted by [0,1]).
The documentation is apparently wrong about the placement is TS[3:2], the
neighbouring read-only bit must be swapped before TS[3:2]. */
typedef volatile struct
{
uint32_t SAR;
uint32_t DAR;
/* Mind that the 8 upper bits should always be written as 0 */
uint32_t TCR;
lword_union(CHCR,
uint32_t :1;
uint32_t LCKN :1; /* Bus Right Release Enable */
uint32_t :2;
uint32_t RPT :3; /* Repeat setting [0..3] */
uint32_t DA :1; /* DREQ Asynchronous [0,1] */
uint32_t DO :1; /* DMA Overrun [0,1] */
uint32_t :1;
uint32_t TS_32 :2; /* Transfer Size (upper half) */
uint32_t HE :1; /* Half-End flag [0..3] */
uint32_t HIE :1; /* Half-end Interrupt Enable [0..3] */
uint32_t AM :1; /* Acknowledge mode [0,1] */
uint32_t AL :1; /* Acknowledge level [0,1] */
uint32_t DM :2; /* Destination address Mode */
uint32_t SM :2; /* Source address Mode */
uint32_t RS :4; /* Resource Select [0,1] */
uint32_t DL :1; /* DREQ Level [0,1] */
uint32_t DS :1; /* DREQ Source select[0,1] */
uint32_t TB :1; /* Transfer Bus Mode */
uint32_t TS_10 :2; /* Transfer Size (lower half) */
uint32_t IE :1; /* Interrupt Enable */
uint32_t TE :1; /* Transfer End flag */
uint32_t DE :1; /* DMA Enable */
);
} GPACKED(4) sh7305_dma_channel_t;
/* sh7305_dma_t - DMA Controller */
typedef volatile struct
{
sh7305_dma_channel_t DMA0;
sh7305_dma_channel_t DMA1;
sh7305_dma_channel_t DMA2;
sh7305_dma_channel_t DMA3;
word_union(OR,
uint16_t CMS :4; /* Cycle steal Mode Select */
uint16_t :2;
uint16_t PR :2; /* PRiority mode */
uint16_t :5;
uint16_t AE :1; /* Address Error flag */
uint16_t NMIF :1; /* NMI Flag */
uint16_t DME :1; /* DMA Master Enable */
);
pad(14);
sh7305_dma_channel_t DMA4;
sh7305_dma_channel_t DMA5;
} GPACKED(4) sh7305_dma_t;
#define SH7305_DMA (*((sh7305_dma_t *)0xfe008020))
#endif /* GINT_MPU_DMA */

View file

@ -1,5 +1,5 @@
//---
// gint:core:intc - Interrupt Controller
// gint:mpu:intc - Interrupt Controller
//
// The interrupt controller is unwieldy because SH7705 and SH7305 have a
// completely different interface. Everything here is split up and you'll
@ -9,8 +9,8 @@
// management. This is probably what you are looking for.
//---
#ifndef GINT_CORE_INTC
#define GINT_CORE_INTC
#ifndef GINT_MPU_INTC
#define GINT_MPU_INTC
#include <gint/defs/types.h>
@ -296,4 +296,4 @@ typedef struct
extern sh7705_intc_t SH7705_INTC;
extern sh7305_intc_t SH7305_INTC;
#endif /* GINT_CORE_INTC */
#endif /* GINT_MPU_INTC */

View file

@ -1,12 +1,12 @@
//---
// gint:core:pfc - Pin Function Controller
// gint:mpu:pfc - Pin Function Controller
//
// The Pin Function Controller has a simple register interface, the main
// difficulty is still understanding the role of its pins.
//---
#ifndef GINT_CORE_PFC
#define GINT_CORE_PFC
#ifndef GINT_MPU_PFC
#define GINT_MPU_PFC
#include <gint/defs/attributes.h>
#include <gint/defs/types.h>
@ -75,4 +75,4 @@ typedef volatile struct
// TODO: Document the SH7305 Pin Function Controller
//---
#endif /* GINT_CORE_PFC */
#endif /* GINT_MPU_PFC */

102
include/gint/mpu/power.h Normal file
View file

@ -0,0 +1,102 @@
//---
// gint:mpu:power- Standby modes and power management
//---
#ifndef GINT_MPU_POWER
#define GINT_MPU_POWER
#include <gint/defs/types.h>
//---
// SH7305 Standby modes and power management Refer to:
// "Renesas SH7724 User's Manual: Hardware"
// Section 18: "Reset and Power-Down Modes"
//---
typedef volatile struct
{
/* Standby Control Register: only one of the bits may be set at any
given time. Setting several bits is prohibited! */
lword_union(STBCR,
uint32_t :24;
uint32_t STBY :1; /* Map [sleep] to standby mode */
uint32_t :1;
uint32_t RSTBY :1; /* Map [sleep] to R-standby mode */
uint32_t USTBY :1; /* Map [sleep] to U-standby mode */
uint32_t :4;
);
pad(12);
/* Module Stop Control Register 0
Stopping the TLB (bit 31), IC (bit 30 or OC (bit 29) seems somewhat
dangerous, plus requires special operations. */
lword_union(MSTPCR0,
uint32_t TLB :1;
uint32_t IC :1;
uint32_t OC :1;
uint32_t RS :1;
uint32_t IL :1;
uint32_t SndCache :1;
uint32_t :1;
uint32_t FPU :1;
uint32_t :1;
uint32_t INTC :1;
uint32_t DMAC0 :1;
uint32_t SuperHyway :1;
uint32_t HUDI :1;
uint32_t DBG :1;
uint32_t UDB :1;
uint32_t Debug :1;
uint32_t TMU0 :1;
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 SCIF2 :1;
uint32_t SCIF3 :1;
uint32_t SCIF4 :1;
uint32_t SCIF5 :1;
uint32_t :1;
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. */
lword_union(MSTPCR2,
uint32_t :6;
uint32_t TPU :1;
uint32_t :4;
uint32_t USB0 :1;
uint32_t :20;
);
pad(4);
/* Boot Address Register
I really don't suggest writing to BAR. */
uint32_t const BAR;
} sh7305_power_t;
#define SH7305_POWER (*((sh7305_power_t *)0xa4150020))
#endif /* GINT_MPU_POWER */

View file

@ -1,9 +1,9 @@
//---
// gint:mod:rtc - Real-Time Clock
// gint:mpu:rtc - Real-Time Clock
//---
#ifndef GINT_CORE_RTC
#define GINT_CORE_RTC
#ifndef GINT_MPU_RTC
#define GINT_MPU_RTC
#include <gint/defs/attributes.h>
@ -75,4 +75,4 @@ typedef volatile struct
#define SH7705_RTC (*((rtc_t *)0xfffffec0))
#define SH7305_RTC (*((rtc_t *)0xa413fec0))
#endif /* GINT_CORE_RTC */
#endif /* GINT_MPU_RTC */

View file

@ -20,8 +20,8 @@ include $(CONFIG)
ifeq "$(CONFIG.TOOLCHAIN)" "sh3eb-elf"
machine := -m3 -mb
endif
ifeq "$(CONFIG.TOOLCHAIN)" "sh4eb-nofpu-elf"
machine := -m4 -mb
ifeq "$(CONFIG.TOOLCHAIN)" "sh4eb-elf"
machine := -m4-nofpu -mb
endif
# Compiler flags, assembler flags, dependency generation, archiving

View file

@ -97,8 +97,12 @@ void bootlog_mapped(int rom, int ram)
print(20, 3, "%c%c", (rom >= (int)rom_size) ? 'F' : 'f',
isSH3() ? 'u' : 'U');
print(9, 2, (ram > 8192) ? "E" : "e");
print(19, 1, "M");
#ifdef FX9860G
print(9, 2, (ram > 8192) ? "E" : "e");
#endif
dupdate();
}
@ -132,7 +136,7 @@ void bootlog_driver(const char *drv, const char *status)
print(x, y, "%3s", drv);
x += 4;
if(x + y >= 22) y++;
if(x + y >= 22) x=1, y++;
/* Positioning for the driver message */

View file

@ -2,14 +2,14 @@
** gint:core:exch - Exception handlers
*/
.global _exch_entry_7305
.global _exch_entry_7305
#ifdef FX9860G
.global _exch_entry_7705
.global _exch_entry_7705
#endif
.section .gint.blocks, "ax"
.align 4
.section .gint.blocks, "ax"
.align 4
/* SH7305-TYPE DEBUG EXCEPTION HANDLER - 26 BYTES */

View file

@ -5,14 +5,14 @@
** blocks depending on its configuration.
*/
.global _inth_entry_7305
.global _inth_entry_7305
#ifdef FX9860G
.global _inth_entry_7705
.global _inth_entry_7705
#endif
.section .gint.blocks, "ax"
.align 4
.section .gint.blocks, "ax"
.align 4
/* Interrupt handlers
@ -100,8 +100,8 @@ _inth_entry_7705:
1: .long 0xa4000000 /* INTEVT2 register */
2: .long _inth_remap
.section .gint.data
.align 4
.section .gint.data
.align 4
/* EVENT CODE TRANSLATION TABLE - 96 BYTES */

140
src/dma/dma.c Normal file
View file

@ -0,0 +1,140 @@
#include <gint/mpu.h>
#include <gint/mpu/dma.h>
#include <gint/mpu/power.h>
#include <gint/mpu/intc.h>
#include <gint/dma.h>
#include <gint/drivers.h>
#include <gint/clock.h>
#define DMA SH7305_DMA
#define INTC SH7305_INTC
#define POWER SH7305_POWER
//---
// Driver interface
//---
/* dma_transfer() - Perform a data transfer */
void dma_transfer(dma_size_t size, uint blocks,
void *src, dma_address_t src_mode,
void *dst, dma_address_t dst_mode)
{
/* Safety guard: only start a transfer if there's not one running */
if(DMA.DMA0.CHCR.DE) return;
/* Disable DMA0 and disable the master DMA switch */
DMA.DMA0.CHCR.DE = 0;
DMA.OR.DME = 0;
/* Set DMA source and target address */
DMA.DMA0.SAR = (uint32_t)src & 0x1fffffff;
DMA.DMA0.DAR = (uint32_t)dst & 0x1fffffff;
/* Set the number of blocks to be transferred */
DMA.DMA0.TCR = blocks;
/* Fill in CHCR. Set RS=0100 (auto-request) and the user-provided
values for TS (transfer size), DM and SM (address modes) */
DMA.DMA0.CHCR.lword = 0x00000400;
DMA.DMA0.CHCR.TS_32 = (size >> 2);
DMA.DMA0.CHCR.TS_10 = (size & 3);
DMA.DMA0.CHCR.DM = dst_mode;
DMA.DMA0.CHCR.SM = src_mode;
DMA.DMA0.CHCR.IE = 1;
/* Prepare DMAOR by enabling the master switch and clearing the
blocking flags. */
DMA.OR.DME = 1;
DMA.OR.AE = 0;
DMA.OR.NMIF = 0;
/* Enable channel 0, starting the DMA transfer. */
DMA.DMA0.CHCR.DE = 1;
}
/* dma_transfer_wait() - Wait for a transfer on channel 0 to finish */
void dma_transfer_wait(void)
{
/* The master switch is cut when the transfer ends */
while(DMA.OR.DME) sleep();
}
//---
// Initialization
//---
static void init(void)
{
/* This driver is not implemented on SH3 */
if(isSH3()) return;
/* Install the interrupt handler from dma/inth.s */
extern void inth_dma_dma0(void);
gint_inthandler(0x800, inth_dma_dma0, 32);
/* Set interrupt priority to 3 */
gint_intlevel(16, 3);
/* Unmask the DMA0 interrupt */
INTC.MSKCLR->IMR1 = 0x01;
}
//---
// Context system for this driver
//---
typedef struct
{
uint32_t SAR0, DAR0, TCR0, CHCR0;
uint16_t OR;
int clock;
} GPACKED(4) ctx_t;
/* One buffer for the system state will go in gint's .bss section */
GBSS static ctx_t sys_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
ctx->SAR0 = DMA.DMA0.SAR;
ctx->DAR0 = DMA.DMA0.DAR;
ctx->TCR0 = DMA.DMA0.TCR;
ctx->CHCR0 = DMA.DMA0.CHCR.lword;
ctx->OR = DMA.OR.word;
/* Save the supply status of the DMA0 clock */
ctx->clock = POWER.MSTPCR0.DMAC0;
}
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
DMA.DMA0.SAR = ctx->SAR0;
DMA.DMA0.DAR = ctx->DAR0;
DMA.DMA0.TCR = ctx->TCR0;
DMA.DMA0.CHCR.lword = ctx->CHCR0;
DMA.OR.word = ctx->OR;
/* Restore the supply status of the DMA0 clock */
POWER.MSTPCR0.DMAC0 = ctx->clock;
}
//---
// Driver structure definition
//---
gint_driver_t drv_dma = {
.name = "DMA",
.init = init,
.ctx_size = sizeof(ctx_t),
.sys_ctx = &sys_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
};
GINT_DECLARE_DRIVER(2, drv_dma);

32
src/dma/inth.s Normal file
View file

@ -0,0 +1,32 @@
/*
** gint:dma:inth - Interrupt handler for the DMA
** An easy one, just clears some flags and marks all transfers as finished.
*/
.global _inth_dma_dma0
.section .gint.blocks, "ax"
.align 4
/* DMA TRANSFER ENDED INTERRUPT HANDLER - BYTES */
_inth_dma_dma0:
/* Clear the TE flag and DMA Enable in CHCR */
mov.l 1f, r1
mov.l @r1, r0
mov #-4, r2
and r2, r0
mov.l r0, @r1
/* Clear the AE and NMIF flags in OR, and cut the master switch */
add #0x34, r1
mov.w @r1, r0
shlr8 r0
shll8 r0
mov.w r0, @r1
rte
nop
nop
nop
1: .long 0xfe00802c /* CHCR0 - OR is 0x34 bytes after this */

View file

@ -2,11 +2,16 @@
// gint:r61524 - Renesas R61524 driver
//---
#include <gint/drivers.h>
#include <gint/defs/types.h>
#include <gint/drivers.h>
#include <gint/dma.h>
#include <core/std.h>
#ifdef FXCG50
#define DMA SH7305_DMA
#define POWER SH7305_POWER
//---
// Device specification sheet
//---
@ -83,21 +88,39 @@ GINLINE static void write(uint16_t data)
}
//---
// Driver functions
// Window management
//---
void pixel(int ha, int va, int color)
void r61524_win_get(uint16_t *HSA, uint16_t *HEA, uint16_t *VSA, uint16_t *VEA)
{
select(ram_address_horizontal);
write(ha);
select(horizontal_ram_start);
*HSA = read();
select(horizontal_ram_end);
*HEA = read();
select(ram_address_vertical);
write(va);
select(write_data);
write(color);
select(vertical_ram_start);
*VSA = read();
select(vertical_ram_end);
*VEA = read();
}
void r61524_win_set(uint16_t HSA, uint16_t HEA, uint16_t VSA, uint16_t VEA)
{
select(horizontal_ram_start);
write(HSA);
select(horizontal_ram_end);
write(HEA);
select(vertical_ram_start);
write(VSA);
select(vertical_ram_end);
write(VEA);
}
//---
// Driver functions
//---
void r61524_test(void)
{
uint16_t device_name;
@ -109,10 +132,6 @@ void r61524_test(void)
uint16_t lpc;
int VEM, COL;
uint32_t AD;
uint16_t HSA, HEA;
uint16_t VSA, VEA;
//---
select(device_code_read);
@ -126,7 +145,7 @@ void r61524_test(void)
{
print(1, 2, "Aborting.");
Bdisp_PutDisp_DD();
delay(40);
getkey();
return;
}
@ -150,22 +169,6 @@ void r61524_test(void)
VEM = (lpc >> 4) & 1;
COL = lpc & 1;
/* Shift by 9, not 8, because of horizontal/vertical range inversion */
select(ram_address_horizontal);
AD = read();
select(ram_address_vertical);
AD |= read() << 9;
select(horizontal_ram_start);
HSA = read();
select(horizontal_ram_end);
HEA = read();
select(vertical_ram_start);
VSA = read();
select(vertical_ram_end);
VEA = read();
//---
print(15, 4, " SM=?");
@ -194,62 +197,53 @@ void r61524_test(void)
print_hex(12, 6, COL, 1);
Bdisp_PutDisp_DD();
delay(50);
getkey();
//---
/* Bdisp_AllClr_VRAM();
print(1, 1, "MSTPCR0=????????");
print_hex(9, 1, POWER.MSTPCR0.lword, 8);
Bdisp_AllClr_VRAM();
print(1, 2, "DMAOR=????");
print_hex(7, 2, DMA.OR.word, 4);
print(1, 1, "Address=?????");
print_hex(9, 1, AD, 5);
print(1, 2, "HSA=??? HEA=???");
print_hex(5, 2, HSA, 3);
print_hex(14, 2, HEA, 3);
print(1, 3, "VSA=??? VEA=???");
print_hex(5, 3, VSA, 3);
print_hex(14, 3, VEA, 3);
print(1, 3, "SAR=????????");
print_hex(5, 3, DMA.DMA0.SAR, 8);
print(1, 4, "DAR=????????");
print_hex(5, 4, DMA.DMA0.DAR, 8);
print(1, 5, "TCR=????????");
print_hex(5, 5, DMA.DMA0.TCR, 8);
print(1, 6, "CHCR=????????");
print_hex(6, 6, DMA.DMA0.CHCR, 8);
Bdisp_PutDisp_DD();
delay(50);
getkey(); */
}
//
Bdisp_AllClr_VRAM();
Bdisp_PutDisp_DD();
//---
select(horizontal_ram_start);
write(0);
select(horizontal_ram_end);
write(395);
select(vertical_ram_start);
write(0);
select(vertical_ram_end);
write(223);
//---
void r61524_dma_test(uint16_t *vram)
{
int y1 = 0;
int height = 224;
/* Move the window to the desired region, then select address 0 */
r61524_win_set(0, 395, y1, y1 + height - 1);
select(ram_address_horizontal);
write(HEA);
write(0);
select(ram_address_vertical);
write(VSA);
write(0);
/* Bind address 0xb4000000 to the data write command */
select(write_data);
uint16_t color;
for(int v = 0; v < 224; v++)
for(int h = 0; h < 396; h++)
{
// int offset = 396 * v + h;
// uint8_t *src = gimp_image.pixel_data + 2 * offset;
color = 0x3eb7; // (src[1] << 8) | src[0];
void *src = vram;
void *dst = (void *)0xb4000000;
write(color);
}
/* The thing is, 396 is not a multiple of 32.
To make things simple, we can choose to always send a multiple of 8
rows, which makes the 32 factor appear. */
int blocks = 198 * (height >> 3);
delay(200);
dma_transfer(DMA_32B, blocks, src, DMA_INC, dst, DMA_FIXED);
dma_transfer_wait();
}
//---
@ -269,33 +263,34 @@ GBSS static ctx_t sys_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
select(horizontal_ram_start);
ctx->HSA = read();
select(horizontal_ram_end);
ctx->HEA = read();
select(vertical_ram_start);
ctx->VSA = read();
select(vertical_ram_end);
ctx->VEA = read();
r61524_win_get(&ctx->HSA, &ctx->HEA, &ctx->VSA, &ctx->VEA);
}
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
select(horizontal_ram_start);
write(ctx->HSA);
select(horizontal_ram_end);
write(ctx->HEA);
select(vertical_ram_start);
write(ctx->VSA);
select(vertical_ram_end);
write(ctx->VEA);
r61524_win_set(ctx->HSA, ctx->HEA, ctx->VSA, ctx->VEA);
}
//---
// Driver status string
//---
#ifdef GINT_BOOT_LOG
/* r6524_status() - status string */
static const char *r6524_status(void)
{
select(device_code_read);
uint16_t dev = read();
static char str[8];
sprintf(str, "%4xF-b", dev);
return str;
}
#endif
//---
// Driver structure definition
//---
@ -303,6 +298,7 @@ static void ctx_restore(void *buf)
gint_driver_t drv_r61524 = {
.name = "R61524",
.init = NULL,
.status = GINT_DRIVER_STATUS(r6524_status),
.ctx_size = sizeof(ctx_t),
.sys_ctx = &sys_ctx,
.ctx_save = ctx_save,

View file

@ -4,10 +4,10 @@
** stop if the callback returns non-zero.
*/
.global _inth_rtc_pri
.global _inth_rtc_pri_helper
.section .gint.blocks, "ax"
.align 4
.global _inth_rtc_pri
.global _inth_rtc_pri_helper
.section .gint.blocks, "ax"
.align 4
/* RTC PERIODIC INTERRUPT HANDLER - 56 BYTES */

View file

@ -5,19 +5,19 @@
** from each interrupt handler to the next.
*/
/* Gates for the standard Timer Unit (TMU) */
.global _inth_tmu_0
.global _inth_tmu_1
.global _inth_tmu_2
.global _inth_tmu_storage
/* Gates for the standard Timer Unit (TMU) */
.global _inth_tmu_0
.global _inth_tmu_1
.global _inth_tmu_2
.global _inth_tmu_storage
/* Gates for the extra timers (informally called ETMU) */
.global _inth_tmu_extra2
.global _inth_tmu_extra_help
.global _inth_tmu_extra_others
/* Gates for the extra timers (informally called ETMU) */
.global _inth_tmu_extra2
.global _inth_tmu_extra_help
.global _inth_tmu_extra_others
.section .gint.blocks, "ax"
.align 4
.section .gint.blocks, "ax"
.align 4
/* TMU INTERRUPT HANDLERS - 128 BYTES
Unfortunately I did not manage to write a handler that cleared the interrupt