Interrupts Added

This commit is contained in:
Peter Weingartner 2024-06-24 21:30:25 -04:00
parent 0dde64c34d
commit ece112a850
4 changed files with 554 additions and 4 deletions

View file

@ -37,7 +37,7 @@ else ifeq ($(UNIT),F256)
AS=as65816 AS=as65816
AR=nlib AR=nlib
SRCS_FOR_UNIT=txt_f256.c indicators_c256.c # interrupts_c256.c timers_c256.c SRCS_FOR_UNIT=txt_f256.c indicators_c256.c interrupts_f256.c # timers_c256.c
CFLAGS_FOR_UNIT=-DMODEL=2 -DCPU=255 --code-model large --data-model large # --target Foenix CFLAGS_FOR_UNIT=-DMODEL=2 -DCPU=255 --code-model large --data-model large # --target Foenix
endif endif

532
src/dev/interrupts_f256.c Normal file
View file

@ -0,0 +1,532 @@
/*
* Definitions for the interrupt controls for the C256 machines
*/
#include <calypsi/intrinsics65816.h>
#include <string.h>
#include "features.h"
#include "interrupt.h"
#include "log.h"
// FoenixMCP interrupt number -> F256 group and mask:
// INT_SOF_A 0x00 --> 0x00, 0x01 (Main screen start-of-frame)
// INT_SOL_A 0x01 --> 0x00, 0x02 (Main screen start-of-line)
// INT_VICKY_A_1 0x02
// INT_VICKY_A_2 0x03
// INT_VICKY_A_3 0x04
// INT_VICKY_A_4 0x05
// INT_RESERVED_1 0x06 --> 0x00, 0x80 (External Expansion)
// INT_VICKY_A_DAC 0x07
// INT_SOF_B 0x08
// INT_SOL_B 0x09
// INT_VICKY_B_1 0x0A
// INT_VICKY_B_2 0x0B
// INT_VICKY_B_3 0x0C
// INT_VICKY_B_4 0x0D
// INT_RESERVED_2 0x0E
// INT_VICKY_B_DAC 0x0F
// INT_KBD_PS2 0x10 --> 0x00, 0x04 (PS/2 Keyboard)
// INT_KBD_A2560K 0x11 --> 0x01, 0x40 (F256K Keyboard)
// INT_MOUSE 0x12 --> 0x00, 0x08 (PS/2 Mouse)
// INT_COM1 0x13 --> 0x01, 0x01 (Serial port 1)
// INT_COM2 0x14
// INT_LPT1 0x15
// INT_FDC 0x16
// INT_MIDI 0x17
// INT_TIMER0 0x18 --> 0x00, 0x10 (Timer 0)
// INT_TIMER1 0x19 --> 0x00, 0x20 (Timer 1)
// INT_TIMER2 0x1A
// INT_TIMER3 0x1B
// INT_TIMER4 0x1C
// INT_RESERVED_3 0x1D
// INT_RESERVED_4 0x1E
// INT_RTC 0x1F --> 0x01, 0x10 (Real time clock)
// INT_PATA 0x20
// INT_SDC_INS 0x21 --> 0x02, 0x80 (SDC inserted)
// INT_SDC 0x22 --> 0x01, 0x80 (SDC)
// INT_OPM_INT 0x23
// INT_OPN2_EXT 0x24
// INT_OPL3_EXT 0x25
// INT_RESERVED_5 0x26
// INT_RESERVED_6 0x27
// INT_BEATRIX_0 0x28
// INT_BEATRIX_1 0x29
// INT_BEATRIX_2 0x2A
// INT_BEATRIX_3 0x2B
// INT_RESERVED_7 0x2C
// INT_DAC1_PB 0x2D
// INT_RESERVED_8 0x2E
// INT_DAC0_PB 0x2F
//
// Interrupt Handler Vectors
//
p_int_handler int_handle_00;
p_int_handler int_handle_01;
p_int_handler int_handle_02;
p_int_handler int_handle_03;
p_int_handler int_handle_04;
p_int_handler int_handle_05;
p_int_handler int_handle_06;
p_int_handler int_handle_07;
p_int_handler int_handle_10;
p_int_handler int_handle_11;
p_int_handler int_handle_12;
p_int_handler int_handle_13;
p_int_handler int_handle_14;
p_int_handler int_handle_15;
p_int_handler int_handle_16;
p_int_handler int_handle_17;
p_int_handler int_handle_20;
p_int_handler int_handle_21;
p_int_handler int_handle_22;
p_int_handler int_handle_23;
p_int_handler int_handle_24;
p_int_handler int_handle_25;
p_int_handler int_handle_26;
p_int_handler int_handle_27;
/**
* @brief Mapping of FoenixMCP interrupt numbers to F256 GABE group numbers (0xff indicates an unassigned interrupt number)
*
*/
static unsigned short g_int_group[] = {
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
0xff, 0x02, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
/**
* @brief Mapping of FoenixMCP interrupt numbers to F256 GABE mask numbers (0xff indicates an unassigned interrupt number)
*
*/
static unsigned short g_int_mask[] = {
0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x04, 0x40, 0x08, 0x01, 0xff, 0xff, 0xff, 0xff, 0x10, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10,
0xff, 0x80, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
/*
* Return the group number for the interrupt number
*/
unsigned short int_group(unsigned short n) {
return g_int_group[n];
}
/*
* Return the mask bit for the interrupt number
*/
unsigned short int_mask(unsigned short n) {
return g_int_mask[n];
}
/*
* Initialize the interrupt registers
*/
void int_init() {
int i;
p_int_handler * int_handlers = &int_handle_00;
// Clear all the interrupt handlers
for (i = 0; i < 4 * 8; i++) {
int_handlers[i] = 0;
}
// At Reset, all of those already have those values
// the Pol are @ 0x0000 and normally pending are reseted, but it is not impossible that some might be triggered during init
*EDGE_GRP0 = 0xFF;
*EDGE_GRP1 = 0xFF;
*EDGE_GRP2 = 0xFF;
*MASK_GRP0 = 0xFF;
*MASK_GRP1 = 0xFF;
*MASK_GRP2 = 0xFF;
// Clear all the pending flags
*PENDING_GRP0 = 0xFF;
*PENDING_GRP1 = 0xFF;
*PENDING_GRP2 = 0xFF;
}
/*
* Enable all interrupts
*
* Returns:
* a machine dependent representation of the interrupt masking prior to enabling
*/
SYSTEMCALL short int_enable_all() {
// NOTE: this code uses Calypsi specific intrinsic functions
// and does a cast that may not be valid
short status = (short)__get_interrupt_state();
__enable_interrupts();
return status;
}
/*
* Disable all interrupts
*
* Returns:
* a machine dependent representation of the interrupt masking prior to disabling
*/
SYSTEMCALL short int_disable_all() {
// NOTE: this code uses Calypsi specific intrinsic functions
// and does a cast that may not be valid
short status = (short)__get_interrupt_state();
__disable_interrupts();
return status;
}
/*
* Disable an interrupt by masking it
*
* Interrupt number is made by the group number and number within the group.
* For instance, the RTC interrupt would be 0x1F and the Channel A SOF interrupt would be 0x00.
*
* Inputs:
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
*/
SYSTEMCALL void int_disable(unsigned short n) {
/* Find the group (the relevant interrupt mask register) for the interrupt */
unsigned short group = int_group(n);
/* Find the mask for the interrupt */
unsigned short mask = int_mask(n);
if ((group != 0xff) && (mask != 0xff)) {
// Only set the mask if the mask and group numbers are valid
uint8_t new_mask = MASK_GRP0[group] | mask;
/* Set the mask bit for the interrupt in the correct MASK register */
MASK_GRP0[group] = new_mask;
}
}
/*
* Enable an interrupt
*
* Interrupt number is made by the group number and number within the group.
* For instance, the RTC interrupt would be 0x1F and the Channel A SOF interrupt would be 0x00.
* And interrupt number of 0xFF specifies that all interrupts should be disabled.
*
* Inputs:
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
*/
SYSTEMCALL void int_enable(unsigned short n) {
/* Find the group (the relevant interrupt mask register) for the interrupt */
unsigned short group = int_group(n);
/* Find the mask for the interrupt */
unsigned short mask = int_mask(n);
printf("Enable interrupt %d => group: %d, mask: %d\n", n, group, mask);
if ((group != 0xff) && (mask != 0xff)) {
// Only set the mask if the mask and group numbers are valid
uint8_t new_mask = MASK_GRP0[group] & ~mask;
/* Clear the mask bit for the interrupt in the correct MASK register */
MASK_GRP0[group] = new_mask;
}
}
/**
* @brief Convert group and mask to an index into a "array" of interrupt handler pointers
*
* @param group the number of the interrupt's group
* @param mask the interupt's mask bit
* @return int the offset to the handler (-1 on error)
*/
static int int_group_mask_to_offset(unsigned short group, unsigned short mask) {
if ((group != 0xff) && (mask != 0xff)) {
unsigned short position = 0;
switch (mask) {
case 0x01:
position = 0;
break;
case 0x02:
position = 1;
break;
case 0x04:
position = 2;
break;
case 0x08:
position = 3;
break;
case 0x10:
position = 4;
break;
case 0x20:
position = 5;
break;
case 0x40:
position = 6;
break;
case 0x80:
position = 7;
break;
default:
break;
}
return group * 8 + position;
} else {
return -1;
}
}
/*
* Register a handler for a given interrupt.
*
* Inputs:
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
* handler = pointer to the interrupt handler to register
*
* Returns:
* the pointer to the previous interrupt handler
*/
SYSTEMCALL p_int_handler int_register(unsigned short n, p_int_handler handler) {
p_int_handler * handler_ref = 0;
p_int_handler old_handler = 0;
/* Find the group (the relevant interrupt mask register) for the interrupt */
unsigned short group = int_group(n);
/* Find the mask for the interrupt */
unsigned short mask = int_mask(n);
switch(group) {
case 0:
switch(mask) {
case 1:
handler_ref = &int_handle_00;
break;
case 2:
handler_ref = &int_handle_01;
break;
case 4:
handler_ref = &int_handle_02;
break;
case 8:
handler_ref = &int_handle_03;
break;
case 16:
handler_ref = &int_handle_04;
break;
case 32:
handler_ref = &int_handle_05;
break;
case 64:
handler_ref = &int_handle_06;
break;
case 128:
handler_ref = &int_handle_07;
break;
default:
return 0;
}
break;
case 1:
switch(mask) {
case 1:
handler_ref = &int_handle_10;
break;
case 2:
handler_ref = &int_handle_11;
break;
case 4:
handler_ref = &int_handle_12;
break;
case 8:
handler_ref = &int_handle_13;
break;
case 16:
handler_ref = &int_handle_14;
break;
case 32:
handler_ref = &int_handle_15;
break;
case 64:
handler_ref = &int_handle_16;
break;
case 128:
handler_ref = &int_handle_17;
break;
default:
return 0;
}
break;
case 2:
switch(mask) {
case 1:
handler_ref = &int_handle_20;
break;
case 2:
handler_ref = &int_handle_21;
break;
case 4:
handler_ref = &int_handle_22;
break;
case 8:
handler_ref = &int_handle_23;
break;
case 16:
handler_ref = &int_handle_24;
break;
case 32:
handler_ref = &int_handle_25;
break;
case 64:
handler_ref = &int_handle_26;
break;
case 128:
handler_ref = &int_handle_27;
break;
default:
return 0;
}
break;
default:
return 0;
}
old_handler = *handler_ref;
*handler_ref = handler;
return old_handler;
}
/*
* Return true (non-zero) if an interrupt is pending for the given interrupt
*
* Inputs:
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
*
* Returns:
* non-zero if interrupt n is pending, 0 if not
*/
SYSTEMCALL short int_pending(unsigned short n) {
/* Find the group (the relevant interrupt mask register) for the interrupt */
unsigned short group = int_group(n);
/* Find the mask for the interrupt */
unsigned short mask = int_mask(n);
if ((group != 0xff) && (mask != 0xff)) {
// Only query the pending mask if the mask and group numbers are valid
return (PENDING_GRP0[group] & mask);
} else {
// If the mask or group number are invalid, just return false
return 0;
}
}
/*
* Acknowledge an interrupt (clear out its pending flag)
*
* Inputs:
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
*/
SYSTEMCALL void int_clear(unsigned short n) {
/* Find the group (the relevant interrupt mask register) for the interrupt */
unsigned short group = int_group(n);
/* Find the mask for the interrupt */
unsigned short mask = int_mask(n);
if ((group != 0xff) && (mask != 0xff)) {
// Only set the mask if the mask and group numbers are valid
uint8_t new_mask = PENDING_GRP0[group] | mask;
/* Set the bit for the interrupt to mark it as cleared */
PENDING_GRP0[group] = new_mask;
}
}
/**
* @brief Handle incomming IRQ signal
*
* NOTE: this routine might not be fast enough in C and have to be replaced by hand written
* assembly code... but we will try it this way first.
*/
__attribute__((interrupt(0xffee))) void int_handle_irq() {
uint8_t mask_bits = 0;
// Process any pending interrupts in group 0
mask_bits = *PENDING_GRP0;
if (mask_bits) {
if ((mask_bits & 0x01) && int_handle_00) int_handle_00(); // Start of frame
if ((mask_bits & 0x02) && int_handle_01) int_handle_01(); // Start of line
if ((mask_bits & 0x04) && int_handle_02) int_handle_02(); // PS/2 Keyboard
if ((mask_bits & 0x08) && int_handle_03) int_handle_03(); // PS/2 Mouse
if ((mask_bits & 0x10) && int_handle_04) int_handle_04(); // Timer 0
if ((mask_bits & 0x20) && int_handle_05) int_handle_05(); // Timer 1
if ((mask_bits & 0x40) && int_handle_06) int_handle_06(); // Reserved
if ((mask_bits & 0x80) && int_handle_07) int_handle_07(); // Cartridge
// Clear the pending bits for group 0
*PENDING_GRP0 = mask_bits;
}
// Process any pending interrupts in group 1
mask_bits = *PENDING_GRP1;
if (mask_bits) {
volatile __attribute__((far)) char * text = (char *)0xafa000;
*text = *text + 1;
if ((mask_bits & 0x01) && int_handle_10) {
volatile __attribute__((far)) char * text = (char *)0xafa001;
*text = *text + 1;
int_handle_10(); // PS/2 Keyboard
}
if ((mask_bits & 0x00) && int_handle_10) int_handle_10(); // UART
if ((mask_bits & 0x10) && int_handle_14) int_handle_14(); // RTC
if ((mask_bits & 0x20) && int_handle_15) int_handle_15(); // VIA
if ((mask_bits & 0x40) && int_handle_16) int_handle_16(); // F256K Matrix Keyboard
if ((mask_bits & 0x80) && int_handle_17) int_handle_17(); // SD card inserted
// Clear the pending bits for group 1
*PENDING_GRP1 = mask_bits;
}
// Process any pending interrupts in group 2
mask_bits = *PENDING_GRP2;
if (mask_bits) {
if ((mask_bits & 0x01) && int_handle_20) int_handle_20(); // IED Data IN
if ((mask_bits & 0x02) && int_handle_21) int_handle_21(); // IED Clock IN
if ((mask_bits & 0x02) && int_handle_22) int_handle_22(); // IED ATN IN
if ((mask_bits & 0x02) && int_handle_22) int_handle_23(); // IED SREQ IN
// Clear the pending bits for group 2
*PENDING_GRP2 = mask_bits;
}
}
/**
* @brief Handle incomming NMI signal
*/
__attribute__((interrupt(0xffea))) void int_handle_nmi() {
}

View file

@ -71,6 +71,24 @@
#define MASK_GRP2 ((volatile uint8_t *)0x00014e) #define MASK_GRP2 ((volatile uint8_t *)0x00014e)
#define MASK_GRP3 ((volatile uint8_t *)0x00014f) #define MASK_GRP3 ((volatile uint8_t *)0x00014f)
#elif MODEL == MODEL_FOENIX_F256 || MODEL == MODEL_FOENIX_F256K || MODEL == MODEL_FOENIX_F256K2
#define PENDING_GRP0 ((volatile uint8_t *)0xf01660)
#define PENDING_GRP1 ((volatile uint8_t *)0xf01661)
#define PENDING_GRP2 ((volatile uint8_t *)0xf01662)
#define POL_GRP0 ((volatile uint8_t *)0xf01664)
#define POL_GRP1 ((volatile uint8_t *)0xf01665)
#define POL_GRP2 ((volatile uint8_t *)0xf01666)
#define EDGE_GRP0 ((volatile uint8_t *)0xf01668)
#define EDGE_GRP1 ((volatile uint8_t *)0xf01669)
#define EDGE_GRP2 ((volatile uint8_t *)0xf0166a)
#define MASK_GRP0 ((volatile uint8_t *)0xf0166c)
#define MASK_GRP1 ((volatile uint8_t *)0xf0166d)
#define MASK_GRP2 ((volatile uint8_t *)0xf0166e)
#endif #endif

View file

@ -144,9 +144,9 @@ void initialize() {
ind_init(); ind_init();
INFO("Indicators initialized"); INFO("Indicators initialized");
// /* Initialize the interrupt system */ /* Initialize the interrupt system */
// int_init(); int_init();
// INFO("Interrupts initialized"); INFO("Interrupts initialized");
/* Mute the PSG */ /* Mute the PSG */
psg_mute_all(); psg_mute_all();