mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 02:53:03 +08:00
Fix timer handling to make IRQ 0 an edge trigger interrupt. Add code to PIC emulation to process said interrupts as edge trigger, do not signal the IRQ unless PIC_DeActivateIRQ() is called, then PIC_ActivateIRQ(). For some reason, this also seems to fix the audio in Tyrian 2000, though the audio still sounds a tiny bit crackly
This commit is contained in:
parent
cf3e9afe95
commit
ba48a170bf
@ -75,6 +75,7 @@ static INLINE pic_tickindex_t PIC_FullIndex(void) {
|
||||
|
||||
void PIC_ActivateIRQ(Bitu irq);
|
||||
void PIC_DeActivateIRQ(Bitu irq);
|
||||
void PIC_EdgeTrigger(Bitu irq,bool set=true);
|
||||
|
||||
void PIC_runIRQs(void);
|
||||
bool PIC_RunQueue(void);
|
||||
|
@ -49,6 +49,8 @@ struct PIC_Controller {
|
||||
bool request_issr;
|
||||
uint8_t vector_base;
|
||||
|
||||
uint8_t input; // input signal (directly set by raise/lower irq) used to filter for edge detect
|
||||
uint8_t edge; // which signals are to be filtered for edge trigger
|
||||
uint8_t irr; // request register
|
||||
uint8_t imr; // mask register
|
||||
uint8_t imrr; // mask register reversed (makes bit tests simpler)
|
||||
@ -92,6 +94,7 @@ struct PIC_Controller {
|
||||
|
||||
void lower_irq(uint8_t val){
|
||||
uint8_t bit = 1 << ( val);
|
||||
input&=~bit;
|
||||
if(irr & bit) { //value will change (as it is currently active)
|
||||
irr&=~bit;
|
||||
if((bit&imrr)&isrr) { //not masked and not in service
|
||||
@ -137,6 +140,11 @@ void PIC_Controller::check_for_irq(){
|
||||
|
||||
void PIC_Controller::raise_irq(uint8_t val){
|
||||
uint8_t bit = 1 << (val);
|
||||
|
||||
// edge detect: only if the signal goes from low to high
|
||||
if (bit&edge&input) return;
|
||||
|
||||
input|=bit;
|
||||
if((irr & bit)==0) { //value changed (as it is currently not active)
|
||||
irr|=bit;
|
||||
if((bit&imrr)&isrr) { //not masked and not in service
|
||||
@ -371,6 +379,25 @@ static void pc_xt_nmi_write(Bitu port,Bitu val,Bitu iolen) {
|
||||
CPU_Check_NMI();
|
||||
}
|
||||
|
||||
void PIC_EdgeTrigger(Bitu irq,bool set) {
|
||||
if (IS_PC98_ARCH) {
|
||||
if (irq == 7) return;
|
||||
}
|
||||
else if (enable_slave_pic) { /* PC/AT emulation with slave PIC cascade to master */
|
||||
if (irq == 2) irq = 9;
|
||||
}
|
||||
else { /* PC/XT emulation with only master PIC */
|
||||
if (irq == 9) irq = 2;
|
||||
if (irq >= 8) return;
|
||||
}
|
||||
|
||||
Bitu t = irq>7 ? (irq - 8): irq;
|
||||
PIC_Controller * pic=&pics[irq>7 ? 1 : 0];
|
||||
|
||||
if (set) pic->edge |= 1u << (unsigned char)t;
|
||||
else pic->edge &= ~(1u << (unsigned char)t);
|
||||
}
|
||||
|
||||
/* FIXME: This should be called something else that's true to the ISA bus, like PIC_PulseIRQ, not Activate IRQ.
|
||||
* ISA interrupts are edge triggered, not level triggered. */
|
||||
void PIC_ActivateIRQ(Bitu irq) {
|
||||
@ -939,6 +966,8 @@ void PIC_Reset(Section *sec) {
|
||||
pics[i].irr = pics[i].isr = pics[i].imrr = 0;
|
||||
pics[i].isrr = pics[i].imr = 0xff;
|
||||
pics[i].isr_ignore = 0x00;
|
||||
pics[i].edge = 0x00;
|
||||
pics[i].input = 0x00;
|
||||
pics[i].active_irq = 8;
|
||||
}
|
||||
|
||||
|
@ -374,7 +374,10 @@ unsigned long PIT_TICK_RATE = PIT_TICK_RATE_IBM;
|
||||
pic_tickindex_t VGA_PITSync_delay(void);
|
||||
|
||||
static void PIT0_Event(Bitu /*val*/) {
|
||||
/* HACK: Despite edge trigger, force IRQ */
|
||||
PIC_DeActivateIRQ(0);
|
||||
PIC_ActivateIRQ(0);
|
||||
|
||||
/* NTS: "Days of Thunder" leaves PIT 0 in mode 1 for some reason, which triggers once and then stops. "start" does not advance in that mode.
|
||||
* For any non-periodic mode, this code would falsely detect an ever increasing error and act badly. */
|
||||
if (pit[0].mode == 2 || pit[0].mode == 3) {
|
||||
@ -468,7 +471,9 @@ static void counter_latch(Bitu counter,bool do_latch=true) {
|
||||
}
|
||||
|
||||
if (counter == 0/*IRQ 0*/) {
|
||||
if (!p->output)
|
||||
if (p->output)
|
||||
PIC_ActivateIRQ(0);
|
||||
else
|
||||
PIC_DeActivateIRQ(0);
|
||||
}
|
||||
}
|
||||
@ -940,6 +945,7 @@ static IO_WriteHandleObject WriteHandler2[4];
|
||||
void TIMER_BIOS_INIT_Configure() {
|
||||
PIC_RemoveEvents(PIT0_Event);
|
||||
PIC_DeActivateIRQ(0);
|
||||
PIC_EdgeTrigger(0,true);
|
||||
|
||||
/* Setup Timer 0 */
|
||||
pit[0].output = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user