From 04231ea5d688dd0750cbe48d497e09d5553f8377 Mon Sep 17 00:00:00 2001 From: lephe Date: Sun, 10 Mar 2019 15:45:34 +0100 Subject: [PATCH] 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. --- README.md | 6 +- configure | 6 +- include/gint/dma.h | 69 +++++++++++++++ include/gint/mpu/cpg.h | 8 +- include/gint/mpu/dma.h | 89 +++++++++++++++++++ include/gint/mpu/intc.h | 8 +- include/gint/mpu/pfc.h | 8 +- include/gint/mpu/power.h | 102 ++++++++++++++++++++++ include/gint/mpu/rtc.h | 8 +- make/Makefile | 4 +- src/core/bootlog.c | 8 +- src/core/exch.S | 8 +- src/core/inth.S | 12 +-- src/dma/dma.c | 140 +++++++++++++++++++++++++++++ src/dma/inth.s | 32 +++++++ src/r61524/r61524.c | 184 +++++++++++++++++++-------------------- src/rtc/inth.s | 8 +- src/tmu/inth.s | 22 ++--- 18 files changed, 578 insertions(+), 144 deletions(-) create mode 100644 include/gint/dma.h create mode 100644 include/gint/mpu/dma.h create mode 100644 include/gint/mpu/power.h create mode 100644 src/dma/dma.c create mode 100644 src/dma/inth.s diff --git a/README.md b/README.md index 4c9aca7..e07e17a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/configure b/configure index cad5b14..2288006 100755 --- a/configure +++ b/configure @@ -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#*=};; diff --git a/include/gint/dma.h b/include/gint/dma.h new file mode 100644 index 0000000..9917946 --- /dev/null +++ b/include/gint/dma.h @@ -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 + +/* 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 */ diff --git a/include/gint/mpu/cpg.h b/include/gint/mpu/cpg.h index 6303d7b..665bbce 100644 --- a/include/gint/mpu/cpg.h +++ b/include/gint/mpu/cpg.h @@ -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 #include @@ -79,4 +79,4 @@ typedef volatile struct #define SH7305_CPG (*((sh7305_cpg_t *)0xa4150000)) -#endif /* GINT_CORE_CPG */ +#endif /* GINT_MPU_CPG */ diff --git a/include/gint/mpu/dma.h b/include/gint/mpu/dma.h new file mode 100644 index 0000000..a7355c3 --- /dev/null +++ b/include/gint/mpu/dma.h @@ -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 + +//--- +// 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 */ diff --git a/include/gint/mpu/intc.h b/include/gint/mpu/intc.h index a1e0c4d..85077f8 100644 --- a/include/gint/mpu/intc.h +++ b/include/gint/mpu/intc.h @@ -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 @@ -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 */ diff --git a/include/gint/mpu/pfc.h b/include/gint/mpu/pfc.h index 8e17e3e..d77df9e 100644 --- a/include/gint/mpu/pfc.h +++ b/include/gint/mpu/pfc.h @@ -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 #include @@ -75,4 +75,4 @@ typedef volatile struct // TODO: Document the SH7305 Pin Function Controller //--- -#endif /* GINT_CORE_PFC */ +#endif /* GINT_MPU_PFC */ diff --git a/include/gint/mpu/power.h b/include/gint/mpu/power.h new file mode 100644 index 0000000..c9ad160 --- /dev/null +++ b/include/gint/mpu/power.h @@ -0,0 +1,102 @@ +//--- +// gint:mpu:power- Standby modes and power management +//--- + +#ifndef GINT_MPU_POWER +#define GINT_MPU_POWER + +#include + +//--- +// 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 */ diff --git a/include/gint/mpu/rtc.h b/include/gint/mpu/rtc.h index 7d5fd50..ae8307f 100644 --- a/include/gint/mpu/rtc.h +++ b/include/gint/mpu/rtc.h @@ -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 @@ -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 */ diff --git a/make/Makefile b/make/Makefile index 7a4c82b..b3b1797 100755 --- a/make/Makefile +++ b/make/Makefile @@ -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 diff --git a/src/core/bootlog.c b/src/core/bootlog.c index b568184..118a84c 100644 --- a/src/core/bootlog.c +++ b/src/core/bootlog.c @@ -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 */ diff --git a/src/core/exch.S b/src/core/exch.S index a7840cb..fcd9733 100644 --- a/src/core/exch.S +++ b/src/core/exch.S @@ -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 */ diff --git a/src/core/inth.S b/src/core/inth.S index 7411838..acffb66 100644 --- a/src/core/inth.S +++ b/src/core/inth.S @@ -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 */ diff --git a/src/dma/dma.c b/src/dma/dma.c new file mode 100644 index 0000000..af9471b --- /dev/null +++ b/src/dma/dma.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/src/dma/inth.s b/src/dma/inth.s new file mode 100644 index 0000000..f955db1 --- /dev/null +++ b/src/dma/inth.s @@ -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 */ diff --git a/src/r61524/r61524.c b/src/r61524/r61524.c index 8d813ba..b5e5d3f 100644 --- a/src/r61524/r61524.c +++ b/src/r61524/r61524.c @@ -2,11 +2,16 @@ // gint:r61524 - Renesas R61524 driver //--- -#include #include +#include +#include +#include #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, diff --git a/src/rtc/inth.s b/src/rtc/inth.s index 270bf98..69544d3 100644 --- a/src/rtc/inth.s +++ b/src/rtc/inth.s @@ -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 */ diff --git a/src/tmu/inth.s b/src/tmu/inth.s index 8e339ec..d5b4fd8 100644 --- a/src/tmu/inth.s +++ b/src/tmu/inth.s @@ -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