diff --git a/src/6502.c b/src/6502.c index c971eb2a..b0602d50 100644 --- a/src/6502.c +++ b/src/6502.c @@ -5858,7 +5858,7 @@ void m65c02_exec(int slice) // printf("INT\n"); } interrupt &= ~128; - if (tube_exec && tubecycle && !(tubeula.r1stat & 0x20)) { + if (tube_exec && tubecycle && !(tubeula.r1stat & TUBE_STAT_P)) { // log_debug("tubeexec %i %i %i\n",tubecycles,tubecycle,tube_shift); tubecycles += (tubecycle * tube_multipler) >> 1; if (tubecycles > 3) diff --git a/src/tube.c b/src/tube.c index 620f2804..4f822cad 100644 --- a/src/tube.c +++ b/src/tube.c @@ -46,21 +46,43 @@ tube_speed_t tube_speeds[NUM_TUBE_SPEEDS] = { "6400%", 64 } }; +enum tube_flow { + TUBE_SPACE_AVAIL = 0x40, + TUBE_DATA_AVAIL = 0x80, + TUBE_BOTH_AVAIL = 0xc0 +}; + int tube_irq=0; tubetype tube_type=TUBEX86; -bool tube_resetting; tube_ula tubeula; +static void tube_reset_most(void) +{ + tubeula.ph1count = tubeula.ph1head = tubeula.ph1tail = 0; + tubeula.ph3pos = 1; + tubeula.hstat[0] = tubeula.hstat[1] = tubeula.hstat[3] = TUBE_SPACE_AVAIL; + tubeula.pstat[0] = TUBE_SPACE_AVAIL; + tubeula.pstat[1] = tubeula.pstat[3] = 0x7f; + tubeula.pstat[2] = 0x3f; + tubeula.hstat[2] = TUBE_BOTH_AVAIL; +} + +void tube_reset(void) +{ + tube_reset_most(); + tubeula.r1stat = 0; +} + void tube_updateints() { int new_irq = 0; interrupt &= ~8; - if ((tubeula.r1stat & 1) && (tubeula.hstat[3] & 128)) + if ((tubeula.r1stat & TUBE_STAT_Q) && (tubeula.hstat[3] & TUBE_DATA_AVAIL)) interrupt |= 8; - if (((tubeula.r1stat & 2) && (tubeula.pstat[0] & 128)) || ((tubeula.r1stat & 4) && (tubeula.pstat[3] & 128))) { + if (((tubeula.r1stat & TUBE_STAT_I) && (tubeula.pstat[0] & TUBE_DATA_AVAIL)) || ((tubeula.r1stat & TUBE_STAT_J) && (tubeula.pstat[3] & TUBE_DATA_AVAIL))) { new_irq |= 1; if (!(tube_irq & 1)) { log_debug("tube: parasite IRQ asserted"); @@ -80,7 +102,7 @@ void tube_updateints() m68k_set_virq(2, 0); } - if (tubeula.r1stat & 8 && (tubeula.ph3pos == 0 || tubeula.hp3pos > (tubeula.r1stat & 16) ? 1 : 0)) { + if (tubeula.r1stat & TUBE_STAT_M && (tubeula.pstat[2] & TUBE_DATA_AVAIL)) { new_irq |= 2; if (!(tube_irq & 2)) { log_debug("tube: parasite NMI asserted"); @@ -106,17 +128,21 @@ uint8_t tube_host_read(uint16_t addr) switch (addr & 7) { case 0: /*Reg 1 Stat*/ - temp = (tubeula.hstat[0] & 0xC0) | tubeula.r1stat; + temp = (tubeula.hstat[0] & TUBE_BOTH_AVAIL) | tubeula.r1stat; break; case 1: /*Register 1*/ - temp = tubeula.ph1[tubeula.ph1head]; - log_debug("tube: host read R%c=%02X", '1', temp); - if (tubeula.ph1count > 0) { + if (tubeula.ph1count > 0) { + temp = tubeula.ph1[tubeula.ph1head]; if (--tubeula.ph1count == 0) - tubeula.hstat[0] &= ~0x80; + tubeula.hstat[0] &= ~TUBE_DATA_AVAIL; if (++tubeula.ph1head == TUBE_PH1_SIZE) tubeula.ph1head = 0; - tubeula.pstat[0] |= 0x40; + tubeula.pstat[0] |= TUBE_SPACE_AVAIL; + log_debug("tube: host read R%c=%02X from FIFO", '1', temp); + } + else { + temp = tubeula.phl; + log_debug("tube: host read R%c=%02X from latch", '1', temp); } break; case 2: /*Register 2 Stat*/ @@ -125,24 +151,26 @@ uint8_t tube_host_read(uint16_t addr) case 3: /*Register 2*/ temp = tubeula.ph2; log_debug("tube: host read R%c=%02X", '2', temp); - if (tubeula.hstat[1] & 0x80) - { - tubeula.hstat[1] &= ~0x80; - tubeula.pstat[1] |= 0x40; - } + tubeula.hstat[1] &= ~TUBE_DATA_AVAIL; + tubeula.pstat[1] |= TUBE_SPACE_AVAIL; break; case 4: /*Register 3 Stat*/ temp = tubeula.hstat[2]; break; case 5: /*Register 3*/ - temp = tubeula.ph3[0]; - log_debug("tube: host read R%c=%02X", '3', temp); - if (tubeula.ph3pos > 0) - { - tubeula.ph3[0] = tubeula.ph3[1]; - tubeula.ph3pos--; - tubeula.pstat[2] |= 0xc0; - if (!tubeula.ph3pos) tubeula.hstat[2] &= ~0x80; + if (tubeula.ph3pos > 0) { + temp = tubeula.ph3[0]; + tubeula.ph3[0] = tubeula.ph3[1]; + tubeula.ph3pos--; + if (!tubeula.ph3pos) { + tubeula.hstat[2] &= ~TUBE_DATA_AVAIL; + tubeula.pstat[2] |= TUBE_BOTH_AVAIL; + } + log_debug("tube: host read R%c=%02X from FIFO", '3', temp); + } + else { + temp = tubeula.phl; + log_debug("tube: host read R%c=%02X from latch", '3', temp); } break; case 6: /*Register 4 Stat*/ @@ -151,11 +179,8 @@ uint8_t tube_host_read(uint16_t addr) case 7: /*Register 4*/ temp = tubeula.ph4; log_debug("tube: host read R%c=%02X", '4', temp); - if (tubeula.hstat[3] & 0x80) - { - tubeula.hstat[3] &= ~0x80; - tubeula.pstat[3] |= 0x40; - } + tubeula.hstat[3] &= ~TUBE_DATA_AVAIL; + tubeula.pstat[3] |= TUBE_SPACE_AVAIL; break; } tube_updateints(); @@ -165,58 +190,54 @@ uint8_t tube_host_read(uint16_t addr) void tube_host_write(uint16_t addr, uint8_t val) { if (!tube_exec) return; + tubeula.hpl = val; + switch (addr & 7) { case 0: /*Register 1 stat*/ - if (val & 0x80) + if (val & TUBE_STAT_S) { + if (val & TUBE_STAT_T && !(tubeula.r1stat & TUBE_STAT_T)) + tube_reset_most(); tubeula.r1stat |= val & 0x3F; - else if (tubeula.r1stat & 0x20) { - tube_reset(); - if (curtube != -1) - tubes[curtube].cpu->reset(); } - else + else { + if (!(val & TUBE_STAT_P) && tubeula.r1stat & TUBE_STAT_P && curtube != -1) + tubes[curtube].cpu->reset(); tubeula.r1stat &= ~(val&0x3F); + + } log_debug("tube: host write S1=%02X->%02X", val, tubeula.r1stat); - tubeula.hstat[0] = (tubeula.hstat[0] & 0xC0) | (val & 0x3F); + tubeula.hstat[0] = (tubeula.hstat[0] & TUBE_BOTH_AVAIL) | (val & 0x3F); break; case 1: /*Register 1*/ log_debug("tube: host write R%c=%02X", '1', val); tubeula.hp1 = val; - tubeula.pstat[0] |= 0x80; - tubeula.hstat[0] &= ~0x40; + tubeula.pstat[0] |= TUBE_DATA_AVAIL; + tubeula.hstat[0] &= ~TUBE_SPACE_AVAIL; break; case 3: /*Register 2*/ log_debug("tube: host write R%c=%02X", '2', val); tubeula.hp2 = val; - tubeula.pstat[1] |= 0x80; - tubeula.hstat[1] &= ~0x40; + tubeula.pstat[1] |= TUBE_DATA_AVAIL; + tubeula.hstat[1] &= ~TUBE_SPACE_AVAIL; break; case 5: /*Register 3*/ - log_debug("tube: host write R%c=%02X", '3', val); - if (tubeula.r1stat & 16) - { - if (tubeula.hp3pos < 2) - tubeula.hp3[tubeula.hp3pos++] = val; - if (tubeula.hp3pos == 2) - { - tubeula.pstat[2] |= 0x80; - tubeula.hstat[2] &= ~0x40; - } + if (tubeula.hp3pos < 2) { + tubeula.hp3[tubeula.hp3pos++] = val; + log_debug("tube: host write R3=%02X (sucessful)", val); + if (tubeula.hp3pos >= ((tubeula.r1stat & TUBE_STAT_V) ? 2 : 1)) { + tubeula.pstat[2] |= TUBE_DATA_AVAIL; /* data available to parasite */ + tubeula.hstat[2] &= ~TUBE_SPACE_AVAIL; /* no space for host */ + } } else - { - tubeula.hp3[0] = val; - tubeula.hp3pos = 1; - tubeula.pstat[2] |= 0x80; - tubeula.hstat[2] &= ~0x40; - } + log_debug("tube: host write R3=%02X (overrun)", val); break; case 7: /*Register 4*/ log_debug("tube: host write R%c=%02X", '4', val); tubeula.hp4 = val; - tubeula.pstat[3] |= 0x80; - tubeula.hstat[3] &= ~0x40; + tubeula.pstat[3] |= TUBE_DATA_AVAIL; + tubeula.hstat[3] &= ~TUBE_SPACE_AVAIL; break; } tube_updateints(); @@ -234,11 +255,8 @@ uint8_t tube_parasite_read(uint32_t addr) case 1: /*Register 1*/ temp = tubeula.hp1; log_debug("tube: parasite read R%c=%02X", '1', temp); - if (tubeula.pstat[0] & 0x80) - { - tubeula.pstat[0] &= ~0x80; - tubeula.hstat[0] |= 0x40; - } + tubeula.pstat[0] &= ~TUBE_DATA_AVAIL; + tubeula.hstat[0] |= TUBE_SPACE_AVAIL; break; case 2: /*Register 2 stat*/ temp = tubeula.pstat[1]; @@ -246,27 +264,26 @@ uint8_t tube_parasite_read(uint32_t addr) case 3: /*Register 2*/ temp = tubeula.hp2; log_debug("tube: parasite read R%c=%02X", '2', temp); - if (tubeula.pstat[1] & 0x80) - { - tubeula.pstat[1] &= ~0x80; - tubeula.hstat[1] |= 0x40; - } + tubeula.pstat[1] &= ~TUBE_DATA_AVAIL; + tubeula.hstat[1] |= TUBE_SPACE_AVAIL; break; case 4: /*Register 3 stat*/ temp = tubeula.pstat[2]; break; case 5: /*Register 3*/ - temp = tubeula.hp3[0]; - log_debug("tube: parasite read R%c=%02X", '3', temp); - if (tubeula.hp3pos>0) - { - tubeula.hp3[0] = tubeula.hp3[1]; - tubeula.hp3pos--; - if (!tubeula.hp3pos) - { - tubeula.hstat[2] |= 0x40; - tubeula.pstat[2] &= ~0x80; - } + if (tubeula.hp3pos > 0) { + temp = tubeula.hp3[0]; + log_debug("tube: parasite read R%c=%02X from FIFO", '3', temp); + tubeula.hp3[0] = tubeula.hp3[1]; + tubeula.hp3pos--; + if (!tubeula.hp3pos) { + tubeula.hstat[2] |= TUBE_SPACE_AVAIL; + tubeula.pstat[2] &= ~TUBE_DATA_AVAIL; + } + } + else { + temp = tubeula.hpl; + log_debug("tube: parasite read R%c=%02X from latch", '3', temp); } break; case 6: /*Register 4 stat*/ @@ -275,11 +292,8 @@ uint8_t tube_parasite_read(uint32_t addr) case 7: /*Register 4*/ temp = tubeula.hp4; log_debug("tube: parasite read R%c=%02X", '4', temp); - if (tubeula.pstat[3] & 0x80) - { - tubeula.pstat[3] &= ~0x80; - tubeula.hstat[3] |= 0x40; - } + tubeula.pstat[3] &= ~TUBE_DATA_AVAIL; + tubeula.hstat[3] |= TUBE_SPACE_AVAIL; break; } tube_updateints(); @@ -288,50 +302,46 @@ uint8_t tube_parasite_read(uint32_t addr) void tube_parasite_write(uint32_t addr, uint8_t val) { + tubeula.phl = val; + switch (addr & 7) { case 1: /*Register 1*/ - log_debug("tube: parasite write R%c=%02X", '1', val); if (tubeula.ph1count < TUBE_PH1_SIZE) { + log_debug("tube: parasite write R%c=%02X (sucessful)", '1', val); tubeula.ph1[tubeula.ph1tail++] = val; - tubeula.hstat[0] |= 0x80; + tubeula.hstat[0] |= TUBE_DATA_AVAIL; if (tubeula.ph1tail == TUBE_PH1_SIZE) tubeula.ph1tail = 0; if (++tubeula.ph1count == TUBE_PH1_SIZE) - tubeula.pstat[0] &= ~0x40; + tubeula.pstat[0] &= ~TUBE_SPACE_AVAIL; } + else + log_debug("tube: parasite write R%c=%02X (overrun)", '1', val); break; case 3: /*Register 2*/ log_debug("tube: parasite write R%c=%02X", '2', val); tubeula.ph2 = val; - tubeula.hstat[1] |= 0x80; - tubeula.pstat[1] &= ~0x40; + tubeula.hstat[1] |= TUBE_DATA_AVAIL; + tubeula.pstat[1] &= ~TUBE_SPACE_AVAIL; break; case 5: /*Register 3*/ - log_debug("tube: parasite write R%c=%02X", '3', val); - if (tubeula.r1stat & 16) - { - if (tubeula.ph3pos < 2) - tubeula.ph3[tubeula.ph3pos++] = val; - if (tubeula.ph3pos == 2) - { - tubeula.hstat[2] |= 0x80; - tubeula.pstat[2] &= ~0x40; - } + if (tubeula.ph3pos < 2) { + log_debug("tube: parasite write R%c=%02X (sucessful)", '3', val); + tubeula.ph3[tubeula.ph3pos++] = val; + if (tubeula.ph3pos >= ((tubeula.r1stat & TUBE_STAT_V) ? 2 : 1)) { + tubeula.hstat[2] |= TUBE_DATA_AVAIL; /* data available to host */ + tubeula.pstat[2] &= ~TUBE_BOTH_AVAIL; /* no space for parasite */ + } } else - { - tubeula.ph3[0] = val; - tubeula.ph3pos = 1; - tubeula.hstat[2] |= 0x80; - tubeula.pstat[2] &= ~0xc0; - } + log_debug("tube: parasite write R%c=%02X (overrun)", '3', val); break; case 7: /*Register 4*/ log_debug("tube: parasite write R%c=%02X", '4', val); tubeula.ph4 = val; - tubeula.hstat[3] |= 0x80; - tubeula.pstat[3] &= ~0x40; + tubeula.hstat[3] |= TUBE_DATA_AVAIL; + tubeula.pstat[3] &= ~TUBE_SPACE_AVAIL; break; } tube_updateints(); @@ -355,26 +365,54 @@ bool tube_32016_init(void *rom) return true; } -void tube_reset(void) -{ - tubeula.ph1count = tubeula.ph1head = tubeula.ph1tail = 0; - tubeula.ph3pos = 1; - tubeula.r1stat = 0; - tubeula.hstat[0] = tubeula.hstat[1] = tubeula.hstat[3] = 0x40; - tubeula.pstat[0] = 0x40; - tubeula.pstat[1] = tubeula.pstat[2] = tubeula.pstat[3] = 0x7f; - tubeula.hstat[2] = 0xC0; -} - void tube_ula_savestate(FILE *f) { - putc(tube_6502_rom_in, f); + uint8_t bytes[2]; + bytes[0] = 2; // version two. + bytes[1] = tube_6502_rom_in; + fwrite(bytes, 2, 1, f); fwrite(&tubeula, sizeof tubeula, 1, f); } void tube_ula_loadstate(FILE *f) { - tube_6502_rom_in = getc(f); - fread(&tubeula, sizeof tubeula, 1, f); + int byte = getc(f); + if (byte == 2) { // version two. + log_debug("tube: loading new tube ULA structure"); + tube_6502_rom_in = getc(f); + fread(&tubeula, sizeof tubeula, 1, f); + } + else { + struct { + uint8_t ph1[TUBE_PH1_SIZE],ph2,ph3[2],ph4; + uint8_t hp1,hp2,hp3[2],hp4; + uint8_t hstat[4],pstat[4],r1stat; + int ph1tail,ph1head,ph1count,ph3pos,hp3pos; + } old_ula; + log_debug("tube: loading old tube ULA structure"); + tube_6502_rom_in = byte; + fread(&old_ula, sizeof(old_ula), 1, f); + for (int i = 0; i < TUBE_PH1_SIZE; ++i) + tubeula.ph1[i] = old_ula.ph1[i]; + tubeula.ph2 = old_ula.ph2; + tubeula.ph3[0] = old_ula.ph3[0]; + tubeula.ph3[1] = old_ula.ph3[1]; + tubeula.ph4 = old_ula.ph4; + tubeula.hp1 = old_ula.hp1; + tubeula.hp2 = old_ula.hp2; + tubeula.hp3[0] = old_ula.hp3[0]; + tubeula.hp3[1] = old_ula.hp3[1]; + tubeula.hp4 = old_ula.hp4; + for (int i = 0; i < 4; ++i) { + tubeula.hstat[i] = old_ula.hstat[i]; + tubeula.pstat[i] = old_ula.pstat[i]; + } + tubeula.r1stat = old_ula.r1stat; + tubeula.ph1tail = old_ula.ph1tail; + tubeula.ph1head = old_ula.ph1head; + tubeula.ph1count = old_ula.ph1count; + tubeula.ph3pos = old_ula.ph3pos; + tubeula.hp3pos = old_ula.hp3pos; + } tube_updateints(); } diff --git a/src/tube.h b/src/tube.h index 0169b411..a574f16d 100644 --- a/src/tube.h +++ b/src/tube.h @@ -32,12 +32,23 @@ extern int tube_speed_num, tube_multipler; #define TUBE_PH1_SIZE 24 +enum tube_status { + TUBE_STAT_Q = 0x01, // enable HIRQ from register 4 + TUBE_STAT_I = 0x02, // enable PIRQ from register 1 + TUBE_STAT_J = 0x04, // enable PIRQ from register 4 + TUBE_STAT_M = 0x08, // enable PNMI from register 3 + TUBE_STAT_V = 0x10, // two byte operation of register 3 + TUBE_STAT_P = 0x20, // activate PRST (reset parasite procoessor) + TUBE_STAT_T = 0x40, // clear all Tube registers (except r1stat). + TUBE_STAT_S = 0x80, // set control flag(s) indicated by mask +}; + typedef struct { - uint8_t ph1[TUBE_PH1_SIZE],ph2,ph3[2],ph4; - uint8_t hp1,hp2,hp3[2],hp4; + uint8_t ph1[TUBE_PH1_SIZE],ph2,ph3[2],ph4,phl; + uint8_t hp1,hp2,hp3[2],hp4,hpl; uint8_t hstat[4],pstat[4],r1stat; - int ph1tail,ph1head,ph1count,ph3pos,hp3pos; + int8_t ph1tail,ph1head,ph1count,ph3pos,hp3pos; } tube_ula; extern tube_ula tubeula;