Merge branch 'feature/midi_in' of https://github.com/86Box/86Box into gus
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user