gint/src/r61524/r61524.c

220 lines
4.5 KiB
C
Raw Permalink Normal View History

//---
// gint:r61524 - Renesas R61524 driver
//---
#include <gint/defs/types.h>
core, tmu: add gint_switch(), return to menu, and improve timer code * Add the gint_switch() function which executes user-provided code from the system (CASIOWIN) context. * Added interrupt masks to the core context (should have been there long ago). * Added the gint_osmenu() function that switches out of gint to invoke GetKeyWait() and inject KEY_CTRL_MENU to trigger the main menu. This uses many CASIOWIN syscalls, but we don't care because gint is unloaded. Trickery is used to catch the key following the return in the add-in and/or display a new application frame before GetKeyWait() even finishes after coming back. This is only available on fx9860g for now. * Removed any public syscall definition to clear up interfaces. * Patched the DMA interruption problem in a weird way on fxcg50, a driver function will be used to do that properly eventually. * Changed the driver model to save driver contexts in preallocated spaces instead of on the stack for overall less risk. * Enabled return-to-menu with the MENU key on fx9860g in getkey(). * Changed the keyboard driver to emit releases before presses, as a return-to-menu acts as a press+release of different keys in a single driver frame, which confuses getkey(). * Fixed a really stupid bug in memcpy() that made the function really not work. Improvements in the timer driver: * Expose ETMU modules as SH7705_TMU and SH7305_TMU in <gint/mpu/tmu.h>. * Remove the timer_t structures, using SH*_ETMU and SH*_TMU instead. Only interrupt gate entries are left hardcoded. * Discovered that not only every write to the TCNT or TCR of an ETMU takes about 1/32k of a second (hinting at registers being powered by the same clock as the timer), but every write occuring while a previous write is pending is *lost*. This led to terrible bugs when switching ETMU contexts too fast in gint_switch(). * Removed an internal timer_address() function. * Overall simplified the handling of timers and the initialization step.
2020-05-10 14:03:41 +02:00
#include <gint/defs/util.h>
#include <gint/hardware.h>
#include <gint/drivers.h>
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
#include <gint/drivers/states.h>
#include <gint/dma.h>
#include <gint/drivers/r61524.h>
#define DMA SH7305_DMA
#define POWER SH7305_POWER
//---
// Device specification sheet
//---
/* Registers and operations */
enum {
device_code_read = 0x000,
driver_output_control = 0x001,
entry_mode = 0x003,
display_control_2 = 0x008,
low_power_control = 0x00b,
ram_address_horizontal = 0x200,
ram_address_vertical = 0x201,
write_data = 0x202,
horizontal_ram_start = 0x210,
horizontal_ram_end = 0x211,
vertical_ram_start = 0x212,
vertical_ram_end = 0x213,
};
typedef word_union(entry_mode_t,
uint TRI :1;
uint DFM :1;
uint :1;
uint BGR :1;
uint :2;
uint HWM :1;
uint :1;
uint ORG :1;
uint :1;
uint ID :2;
uint AM :1;
uint :1;
uint EPF :2;
);
//---
// Device communication primitives
//---
/* Interface with the controller */
static volatile uint16_t *intf = (void *)0xb4000000;
/* Bit 4 of Port R controls the RS bit of the display driver */
static volatile uint8_t *PRDR = (void *)0xa405013c;
GINLINE static void select(uint16_t reg)
{
/* Clear RS and write the register number */
*PRDR &= ~0x10;
synco();
*intf = reg;
synco();
/* Set RS back. We don't do this in read()/write() because the display
driver is optimized for consecutive GRAM access. LCD-transfers will
be faster when executing select() followed by several calls to
write(). (Although most applications should use the DMA instead.) */
*PRDR |= 0x10;
synco();
}
GINLINE static uint16_t read(void)
{
return *intf;
}
GINLINE static void write(uint16_t data)
{
*intf = data;
}
uint16_t r61524_get(int ID)
{
select(ID);
return read();
}
void r61524_set(int ID, uint16_t value)
{
select(ID);
write(value);
}
//---
// Window management
//---
void r61524_win_get(uint16_t *HSA, uint16_t *HEA, uint16_t *VSA, uint16_t *VEA)
{
select(horizontal_ram_start);
*HSA = read();
select(horizontal_ram_end);
*HEA = read();
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
//---
/* TODO: r61524: update, backlight, brightness, gamma */
void r61524_start_frame(int xmin, int xmax, int ymin, int ymax)
{
/* Move the window to the desired region, then select address 0 */
r61524_win_set(395-xmax, 395-xmin, ymin, ymax);
select(ram_address_horizontal);
write(0);
select(ram_address_vertical);
write(0);
/* Bind address 0xb4000000 to the data write command */
select(write_data);
}
void r61524_display(uint16_t *vram, int start, int height, int method)
{
/* Wait for any transfer to finish before using the screen, otherwise
the DMA might write data *while* we're sending commands! */
dma_transfer_wait(0);
r61524_start_frame(0, 395, start, start + height - 1);
if(method == R61524_CPU)
{
for(int i = 0; i < 396 * height; i++)
write(vram[i + 396 * start]);
return;
}
void *src = (void *)vram + start * 396*2;
void *dst = (void *)0xb4000000;
/* The amount of data sent per row, 396*2, is not a multiple of 32. For
now I assume [height] is a multiple of 4, which makes the factor 32
appear. */
int blocks = 99 * (height >> 2);
if(method == R61524_DMA) {
dma_transfer_async(0, DMA_32B, blocks, src, DMA_INC, dst,
DMA_FIXED, GINT_CALL_NULL);
}
else {
/* Transfer atomically */
dma_transfer_atomic(0, DMA_32B, blocks, src, DMA_INC, dst,
DMA_FIXED);
}
}
void r61524_display_rect(uint16_t *vram, int xmin, int xmax, int ymin,
int ymax)
{
dma_transfer_wait(0);
r61524_start_frame(xmin, xmax, ymin, ymax);
vram += 396 * ymin + xmin;
for(int y = 0; y < ymax - ymin + 1; y++) {
for(int x = 0; x < xmax - xmin + 1; x++)
write(vram[x]);
vram += 396;
}
}
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
// State and driver metadata
//---
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void hsave(r61524_state_t *s)
{
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
r61524_win_get(&s->HSA, &s->HEA, &s->VSA, &s->VEA);
}
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
static void hrestore(r61524_state_t const *s)
{
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
r61524_win_set(s->HSA, s->HEA, s->VSA, s->VEA);
}
gint_driver_t drv_r61524 = {
.name = "R61524",
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
.hsave = (void *)hsave,
.hrestore = (void *)hrestore,
.state_size = sizeof(r61524_state_t),
};
kernel: driver and world system overhaul Changes in the driver and world system: * Rewrite driver logic to include more advanced concepts. The notion of binding a driver to a device is introduced to formalize wait(); power management is now built-in instead of being handled by the drivers (for instance DMA). The new driver model is described in great detail in <gint/drivers.h> * Formalized the concept of "world switch" where the hardware state is saved and later restored. As a tool, the world switch turns out to be very stable, and allows a lot of hardware manipulation that would be edgy at best when running in the OS world. * Added a GINT_DRV_SHARED flag for drivers to specify that their state is shared between worlds and not saved/restored. This has a couple of uses. * Exposed a lot more of the internal driver/world system as their is no particular downside to it. This includes stuff in <gint/drivers.h> and the driver's state structures in <gint/drivers/states.h>. This is useful for debugging and for cracked concepts, but there is no API stability guarantee. * Added a more flexible driver level system that allows any 2-digit level to be used. Feature changes: * Added a CPU driver that provides the VBR change as its state save. Because the whole context switch relied on interrupts being disabled anyway, there is no longer an inversion of control when setting the VBR; this is just part of the CPU driver's configuration. The CPU driver may also support other features such as XYRAM block transfer in the future. * Moved gint_inthandler() to the INTC driver under the name intc_handler(), pairing up again with intc_priority(). * Added a reentrant atomic lock based on the test-and-set primitive. Interrupts are disabled with IMASK=15 for the duration of atomic operations. * Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides little benefit on this platform because the RAM is generally faster and buffers are ultimately small. The DMA is still not available on SH3-based fx-9860G models. * Solved an extremely obnoxious bug in timer_spin_wait() where the timer is not freed, causing the callback to be called when interrupts are re-enabled. This increments a random value on the stack. As a consequence of the change, removed the long delays in the USB driver since they are not actually needed. Minor changes: * Deprecated some of the elements in <gint/hardware.h>. There really is no good way to "enumerate" devices yet. * Deprecated gint_switch() in favor of a new function gint_world_switch() which uses the GINT_CALL abstraction. * Made the fx-9860G VRAM 32-aligned so that it can be used for tests with the DMA. Some features of the driver and world systems have not been implemented yet, but may be in the future: * Some driver flags should be per-world in order to create multiple gint worlds. This would be useful in Yatis' hypervisor. * A GINT_DRV_LAZY flag would be useful for drivers that don't want to be started up automatically during a world switch. This is relevant for drivers that have a slow start/stop sequence. However, this is tricky to do correctly as it requires dynamic start/stop and also tracking which world the current hardware state belongs to.
2021-04-23 18:50:20 +02:00
GINT_DECLARE_DRIVER(26, drv_r61524);