Merge branch 'feature/midi_in' of https://github.com/86Box/86Box into gus

This commit is contained in:
Altheos
2020-01-08 18:52:16 +01:00

View File

@@ -13,6 +13,7 @@
#include "../timer.h"
#include "../device.h"
#include "sound.h"
#include "midi.h"
#include "snd_gus.h"
enum
@@ -100,9 +101,9 @@ typedef struct gus_t
uint8_t ad_status, ad_data;
uint8_t ad_timer_ctrl;
uint8_t midi_ctrl, midi_status;
uint8_t midi_data;
int midi_loopback;
uint8_t uart_queue[64];
int uart_pos, uart_used;
int uart_in, uart_out, sysex;
uint8_t gp1, gp2;
uint16_t gp1_addr, gp2_addr;
@@ -111,7 +112,6 @@ typedef struct gus_t
} gus_t;
static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15};
static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15};
static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1};
int gusfreqs[]=
@@ -151,31 +151,6 @@ void pollgusirqs(gus_t *gus)
if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq);
}
void gus_midi_update_int_status(gus_t *gus)
{
gus->midi_status &= ~MIDI_INT_MASTER;
if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT))
{
gus->midi_status |= MIDI_INT_MASTER;
gus->irqstatus |= GUS_INT_MIDI_TRANSMIT;
}
else
gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT;
if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE))
{
gus->midi_status |= MIDI_INT_MASTER;
gus->irqstatus |= GUS_INT_MIDI_RECEIVE;
}
else
gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE;
if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1))
{
picint(1 << gus->irq_midi);
}
}
void writegus(uint16_t addr, uint8_t val, void *p)
{
gus_t *gus = (gus_t *)p;
@@ -188,34 +163,34 @@ void writegus(uint16_t addr, uint8_t val, void *p)
else
port = addr & 0xf0f;
if (gus->latch_enable && port != 0x20b)
gus->latch_enable = 0;
switch (port)
{
case 0x300: /*MIDI control*/
old = gus->midi_ctrl;
gus->midi_ctrl = val;
if ((val & 3) == 3)
gus->midi_status = 0;
else if ((old & 3) == 3)
{
gus->midi_status |= MIDI_INT_TRANSMIT;
}
gus_midi_update_int_status(gus);
gus->uart_out = 1;
if (val == 3 || !val) {
gus->uart_in = 0;
gus->irqstatus &= ~0x03;
gus->uart_used = 0;
return;
}
if (val & 0x20) {
gus->irqstatus |= 0x01;
} else {
gus->irqstatus &= ~0x01;
}
if (val & 0x80)
gus->uart_in = 1;
else
gus->uart_in = 0;
break;
case 0x301: /*MIDI data*/
if (gus->midi_loopback)
{
gus->midi_status |= MIDI_INT_RECEIVE;
gus->midi_data = val;
if (gus->uart_out) {
midi_raw_out_byte(val);
picint(1 << gus->irq_midi);
}
else
gus->midi_status |= MIDI_INT_TRANSMIT;
break;
break;
case 0x302: /*Voice select*/
gus->voice=val&31;
break;
@@ -246,11 +221,11 @@ void writegus(uint16_t addr, uint8_t val, void *p)
gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val;
break;
case 0x6: /*Ramp frequency*/
case 6: /*Ramp frequency*/
gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
break;
case 0x9: /*Current volume*/
case 9: /*Current volume*/
gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6);
break;
@@ -278,10 +253,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8);
switch (gus->global)
{
case 0: /*Voice control*/
if (!(val&1) && gus->ctrl[gus->voice]&1)
{
}
gus->ctrl[gus->voice] = val & 0x7f;
old = gus->waveirqs[gus->voice];
@@ -309,16 +280,16 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8);
gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8);
break;
case 0x6: /*Ramp frequency*/
case 6: /*Ramp frequency*/
gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6))));
break;
case 0x7: /*Ramp start*/
case 7: /*Ramp start*/
gus->rstart[gus->voice] = val << 14;
break;
case 0x8: /*Ramp end*/
case 8: /*Ramp end*/
gus->rend[gus->voice] = val << 14;
break;
case 0x9: /*Current volume*/
case 9: /*Current volume*/
gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14);
break;
@@ -510,33 +481,75 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8);
break;
case 0x200:
gus->midi_loopback = val & 0x20;
gus->latch_enable = (val & 0x40) ? 2 : 1;
gus->latch_enable = val;
break;
case 0x20b:
switch (gus->reg_ctrl & 0x07)
{
case 0:
if (gus->latch_enable == 1)
gus->dma = gus_dmas[val & 7];
if (gus->latch_enable == 2)
{
gus->irq = gus_irqs[val & 7];
if (val & 0x40)
{
if (gus->irq == -1)
gus->irq = gus->irq_midi = gus_irqs[(val >> 3) & 7];
else
gus->irq_midi = gus->irq;
}
else
gus->irq_midi = gus_irqs_midi[(val >> 3) & 7];
gus->sb_nmi = val & 0x80;
}
gus->latch_enable = 0;
if (gus->latch_enable & 0x40) {
// GUS SDK: IRQ Control Register
// Channel 1 GF1 IRQ selector (bits 2-0)
// 0=reserved, do not use
// 1=IRQ2
// 2=IRQ5
// 3=IRQ3
// 4=IRQ7
// 5=IRQ11
// 6=IRQ12
// 7=IRQ15
// Channel 2 MIDI IRQ selector (bits 5-3)
// 0=no interrupt
// 1=IRQ2
// 2=IRQ5
// 3=IRQ3
// 4=IRQ7
// 5=IRQ11
// 6=IRQ12
// 7=IRQ15
// Combine both IRQs using channel 1 (bit 6)
// Reserved (bit 7)
//
// "If both channels are sharing an IRQ, channel 2's IRQ must be set to 0 and turn on bit 6. A
// bus conflict will occur if both latches are programmed with the same IRQ #."
if (gus_irqs[val & 7] != -1)
gus->irq = gus_irqs[val & 7];
if (val & 0x40) // "Combine both IRQs"
gus->irq_midi = gus->irq;
else
gus->irq_midi = gus_irqs[(val >> 3) & 7];
gus->sb_nmi = val & 0x80;
} else {
// GUS SDK: DMA Control Register
// Channel 1 (bits 2-0)
// 0=NO DMA
// 1=DMA1
// 2=DMA3
// 3=DMA5
// 4=DMA6
// 5=DMA7
// 6=?
// 7=?
// Channel 2 (bits 5-3)
// 0=NO DMA
// 1=DMA1
// 2=DMA3
// 3=DMA5
// 4=DMA6
// 5=DMA7
// 6=?
// 7=?
// Combine both DMA channels using channel 1 (bit 6)
// Reserved (bit 7)
//
// "If both channels are sharing an DMA, channel 2's DMA must be set to 0 and turn on bit 6. A
// bus conflict will occur if both latches are programmed with the same DMA #."
if (gus_dmas[val & 7] != -1)
gus->dma = gus_dmas[val & 7];
}
break;
case 1:
gus->gp1 = val;
@@ -559,13 +572,12 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8);
break;
case 0x206:
gus->ad_status |= 0x08;
if (gus->sb_ctrl & 0x20)
{
if (gus->sb_ctrl & 0x20) {
gus->ad_status |= 0x08;
if (gus->sb_nmi)
nmi = 1;
nmi = 1;
else if (gus->irq != -1)
picint(1 << gus->irq);
picint(1 << gus->irq);
}
break;
case 0x20a:
@@ -607,26 +619,49 @@ uint8_t readgus(uint16_t addr, void *p)
switch (port)
{
case 0x300: /*MIDI status*/
val = gus->midi_status;
val = ((gus->irqstatus & 0x03 ? 0x80 : 0) |
(gus->uart_in && gus->uart_used >= 64 ? 0x20:0) |
((gus->uart_used && gus->uart_in) ? 1 : 0) | (gus->uart_out ? 2 : 0));
break;
case 0x301: /*MIDI data*/
val = gus->midi_data;
gus->midi_status &= ~MIDI_INT_RECEIVE;
gus_midi_update_int_status(gus);
val = 0;
if (gus->uart_in) {
if (gus->uart_used) {
if (gus->uart_pos >= 64)
gus->uart_pos -= 64;
val = gus->uart_queue[gus->uart_pos];
gus->uart_pos++;
gus->uart_used--;
}
if (!gus->uart_used)
gus->irqstatus &= ~0x02;
}
break;
case 0x200: return 0;
case 0x206: /*IRQ status*/
case 0x200:
val = 0xff;
break;
case 0x206: /*IRQ status*/
val = gus->irqstatus & ~0x10;
if (gus->ad_status & 0x19)
val |= 0x10;
return val;
break;
case 0x20F: return 0;
case 0x302: return gus->voice;
case 0x303: return gus->global;
case 0x304: /*Global low*/
case 0x20F:
val = 0;
break;
case 0x302:
val = gus->voice;
break;
case 0x303:
val = gus->global;
break;
case 0x304: /*Global low*/
switch (gus->global)
{
case 0x82: /*Start addr high*/
@@ -798,7 +833,6 @@ void gus_poll_timer_1(void *p)
if (gus->irq != -1)
picint(1 << gus->irq);
}
gus_midi_update_int_status(gus);
}
void gus_poll_timer_2(void *p)
@@ -1026,6 +1060,55 @@ static void gus_get_buffer(int32_t *buffer, int len, void *p)
gus->pos = 0;
}
static void gus_queue(gus_t *gus, uint8_t val)
{
int pos;
if (gus->uart_used < 64) {
pos = gus->uart_used + gus->uart_pos;
if (pos >= 64)
pos -= 64;
gus->uart_queue[pos] = val;
gus->uart_used++;
}
}
static void gus_input_msg(void *p, uint8_t *msg)
{
gus_t *gus = (gus_t *)p;
uint8_t i;
if (gus->sysex)
return;
if (gus->uart_in) {
gus->irqstatus |= 0x02;
for (i=0;i<msg[3];i++)
gus_queue(gus, msg[i]);
picint(1 << gus->irq_midi);
}
}
static int gus_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort)
{
gus_t *gus = (gus_t *)p;
uint32_t i;
if (abort) {
gus->uart_used = 0;
gus->sysex = 0;
return 0;
}
gus->sysex = 1;
for (i=0;i<len;i++) {
if (gus->uart_used >= 64) {
return (len-i);
}
gus_queue(gus, buffer[i]);
}
gus->sysex = 0;
return 0;
}
void *gus_init(const device_t *info)
{
@@ -1062,6 +1145,7 @@ void *gus_init(const device_t *info)
io_sethandler(gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus);
io_sethandler(0x0100+gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus);
io_sethandler(0x0506+gus->base, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus);
io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus);
timer_add(&gus->samp_timer, gus_poll_wave, gus, 1);
timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1);
@@ -1069,6 +1153,10 @@ void *gus_init(const device_t *info)
sound_add_handler(gus_get_buffer, gus);
input_msg = gus_input_msg;
input_sysex = gus_input_sysex;
midi_in_p = gus;
return gus;
}