/******************************************************************************* * NewOswan * interrupt_controller.c: * * Created by mlt on 14/03/2022. * Copyright (c) 2022 986-Studio. All rights reserved. * ******************************************************************************/ #include #include #include #include #include /* device internal parameters */ typedef struct ic_params_t { uint8_t address_base; uint8_t int_enable_mask; uint8_t int_status; } ic_params_t; static ic_params_t interrupt_controller; static uint8_t IC_IO_read(void *pdata, uint8_t port) { ic_params_t *params = (ic_params_t *)pdata; switch(port) { case 0xB0: return params->address_base; case 0xB2: return params->int_enable_mask; case 0xB4: return params->int_status; } return 0x00; } static void IC_IO_write(void *pdata, uint8_t port, uint8_t value) { ic_params_t *params = (ic_params_t *)pdata; switch(port) { case 0xB0: params->address_base = value; break; case 0xB2: params->int_enable_mask = value; break; } } static void IC_IO_write_ack(void *pdata, uint8_t port, uint8_t value) { ic_params_t *params = (ic_params_t *)pdata; // De-assert CPU interrupt accordingly to the mask in value } static void IC_init(void *params) { UNUSED_PARAMETER(params); register_io_hook(0xB0, IC_IO_read, IC_IO_write, &interrupt_controller); register_io_hook(0xB2, IC_IO_read, IC_IO_write, &interrupt_controller); register_io_hook(0xB4, IC_IO_read, NULL, &interrupt_controller); register_io_hook(0xB6, NULL, IC_IO_write_ack, &interrupt_controller); } static void IC_reset() { interrupt_controller.int_enable_mask = 0; interrupt_controller.address_base = 0; } static void IC_free() { } device_t InterruptController = { .init = IC_init, .reset = IC_reset, .free = IC_free, .deviceType = DT_INTERRUPT_CONTROLLER, }; /* Exported functions */ void trigger_interrupt(hw_interrupt_type_t type) { uint16_t int_vector = interrupt_controller.address_base & 0xF8 + (uint8_t)type; /* Check that the INT is enabled */ if ((interrupt_controller.int_enable_mask >> type) & 0x1) { /* TODO: Do we have to enable that even if the int is not enabled? */ interrupt_controller.int_status |= (1 << type); // Fire the NEC interrupt } }