| /*<empty clipboard> |
| YAPE - Yet Another Plus/4 Emulator |
| |
| The program emulates the Commodore 264 family of 8 bit microcomputers |
| |
| This program is free software, you are welcome to distribute it, |
| and/or modify it under certain conditions. For more information, |
| read 'Copying'. |
| |
| (c) 2000, 2001, 2004, 2005 Attila Grósz |
| */ |
| #include <stdio.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include "Tedmem.h" |
| #include "Sid.h" |
| #include "Cpu.h" |
| #include "roms.h" |
| #include "Filter.h" |
| |
| #define TEXTMODE 0x00000000 |
| #define MULTICOLOR 0x00000010 |
| #define GRAPHMODE 0x00000020 |
| #define EXTCOLOR 0x00000040 |
| #define REVERSE 0x00000080 |
| #define ILLEGAL 0x0000000F |
| |
| static unsigned int VertSubCount; |
| static int x,tmp; |
| static unsigned char *VideoBase; |
| |
| ClockCycle TED::CycleCounter; |
| static bool ScreenOn, AttribFetch; |
| static bool SideBorderFlipFlop, CharacterWindow; |
| static unsigned int BadLine; |
| static unsigned int ClockingState; |
| static unsigned int CharacterCount = 0; |
| static bool VertSubActive; |
| static unsigned int CharacterPosition; |
| static unsigned int CharacterPositionReload; |
| static unsigned int TVScanLineCounter; |
| static bool HBlanking; |
| static bool VBlanking; |
| static bool aligned_write; |
| static unsigned char *aw_addr_ptr; |
| static unsigned char aw_value; |
| static unsigned int ff1d_latch; |
| TED *TED::instance_; |
| |
| enum { |
| TSS = 1 << 1, |
| TDS = 1 << 2, |
| TRFSH = 1 << 3, |
| THALT1 = 1 << 4, |
| THALT2 = 1 << 5, |
| THALT3 = 1 << 6, |
| TDMA = 1 << 7 |
| }; |
| |
| TED::TED() : filter(0), sidCard(0) |
| { |
| register unsigned int i; |
| |
| instance_ = this; |
| // clearing cartdridge ROMs |
| for (i=0;i<4;++i) { |
| memset(&(RomHi[i]),0,ROMSIZE); |
| memset(&(RomLo[i]),0,ROMSIZE); |
| memset(romlopath,0,sizeof(romlopath)); |
| memset(romhighpath,0,sizeof(romhighpath)); |
| }; |
| // default ROM sets |
| strcpy(romlopath[0],"BASIC"); |
| strcpy(romhighpath[0],"KERNAL"); |
| |
| // 64 kbytes of memory allocated |
| RAMMask=0xFFFF; |
| |
| // actual ram bank pointer default setting |
| actram=Ram; |
| |
| // setting screen memory pointer |
| scrptr=screen; |
| // pointer of the end of the screen memory |
| endptr=scrptr+456*312-8; |
| // setting the CPU to fast mode |
| fastmode=1; |
| // initial position of the electron beam (upper left corner) |
| irqline=VertSubCount=0; |
| beamy=0; |
| beamx=0; |
| hshift = 0; |
| scrblank= false; |
| |
| charrombank=charrambank=cset=VideoBase=Ram; |
| scrattr=0; |
| timer1=timer2=timer3=0; |
| chrbuf = DMAbuf; |
| clrbuf = DMAbuf + 64; |
| tmpClrbuf = DMAbuf + 128; |
| memset(DMAbuf, 0, sizeof(DMAbuf)); |
| |
| // create an instance of the keyboard class |
| // keys = new KEYS; |
| // tap = new TAP; |
| // setting the TAP::mem pointer to this MEM class |
| // tap->mem=this; |
| // tcbmbus = NULL; |
| crsrblinkon = false; |
| VertSubActive = false; |
| CharacterPositionReload = CharacterPosition = 0; |
| SideBorderFlipFlop = false; |
| render_ok = false; |
| |
| BadLine = 0; |
| CycleCounter = 0; |
| oscillatorInit(); |
| memset(protectedPlayerMemory, 0xfe, sizeof(protectedPlayerMemory)); |
| enableSidCard(true, 0); |
| } |
| |
| void TED::Reset() |
| { |
| // clear RAM with powerup pattern |
| for (int i=0;i<RAMSIZE;Ram[i++] = (i>>1)<<1==i ? 0 : 0xFF); |
| // reset oscillators |
| oscillatorReset(); |
| if (sidCard) sidCard->reset(); |
| lastResetCycle = CycleCounter; |
| } |
| |
| void TED::forcedReset() |
| { |
| ChangeMemBankSetup(false); |
| Reset(); |
| } |
| |
| void TED::texttoscreen(int x,int y, const char *scrtxt) |
| { |
| register int i =0; |
| |
| while (scrtxt[i]!=0) |
| chrtoscreen(x+i*8,y,scrtxt[i++]); |
| } |
| |
| void TED::chrtoscreen(int x,int y, char scrchr) |
| { |
| register int j, k; |
| unsigned char *charset = (unsigned char *) kernal+0x1000; |
| |
| if (isalpha(scrchr)) { |
| scrchr=toupper(scrchr)-64; |
| charset+=(scrchr<<3); |
| for (j=0;j<8;j++) |
| for (k=0;k<8;k++) |
| (*(charset+j) & (0x80>>k)) ? screen[(y+j)*456+x+k]=0x00 : screen[(y+j)*456+x+k]=0x71; |
| return; |
| } |
| charset+=(scrchr<<3); |
| for (j=0;j<8;j++) |
| for (k=0;k<8;k++) |
| (*(charset+j) & (0x80>>k)) ? screen[(y+j)*456+x+k]=0x00 : screen[(y+j)*456+x+k]=0x71; |
| } |
| |
| void TED::loadroms() |
| { |
| for (int i=0;i<4;i++) { |
| loadhiromfromfile(i,romhighpath[i]); |
| loadloromfromfile(i,romlopath[i]); |
| } |
| mem_8000_bfff = actromlo = &(RomLo[0][0]); |
| mem_fc00_fcff = mem_c000_ffff = actromhi = &(RomHi[0][0]); |
| } |
| |
| void TED::loadloromfromfile(int nr, char fname[512]) |
| { |
| FILE *img; |
| |
| if (fname[0]!='\0') { |
| if (img = fopen(fname, "rb")) { |
| // load low ROM file |
| fread(&(RomLo[nr]),ROMSIZE,1,img); |
| fclose(img); |
| return; |
| } |
| switch (nr) { |
| case 0: memcpy(&(RomLo[0]),basic,ROMSIZE); |
| break; |
| case 1: if (!strncmp(fname,"3PLUS1LOW",9)) |
| memcpy(&(RomLo[1]),plus4lo,ROMSIZE); |
| else |
| memset(&(RomLo[1]),0,ROMSIZE); |
| break; |
| default : memset(&(RomLo[nr]),0,ROMSIZE); |
| } |
| } else |
| memset(&(RomLo[nr]),0,ROMSIZE); |
| } |
| |
| void TED::loadhiromfromfile(int nr, char fname[512]) |
| { |
| FILE *img; |
| |
| if (fname[0]!='\0') { |
| if (img = fopen(fname, "rb")) { |
| // load high ROM file |
| fread(&(RomHi[nr]),ROMSIZE,1,img); |
| fclose(img); |
| return; |
| } |
| switch (nr) { |
| case 0: |
| memcpy(&(RomHi[0]),kernal,ROMSIZE); |
| break; |
| case 1: if (!strncmp(fname,"3PLUS1HIGH",10)) |
| memcpy(&(RomHi[1]),plus4hi,ROMSIZE); |
| else |
| memset(&(RomHi[1]),0,ROMSIZE); |
| break; |
| default : memset(&(RomHi[nr]),0,ROMSIZE); |
| } |
| } else |
| memset(&(RomHi[nr]),0,ROMSIZE); |
| } |
| |
| void TED::injectCodeToRAM(unsigned int address, unsigned char *from, size_t len) |
| { |
| size_t bytes = (address + len > 0xffff) ? 0xffff - address : len; |
| memcpy(actram + (address & 0xffff), from, bytes); |
| } |
| |
| void TED::copyToKbBuffer(char *bufferString, unsigned int bufferLength) |
| { |
| unsigned int bufferAddress = 0x0527; |
| if (bufferLength == -1) bufferLength = (unsigned int) strlen(bufferString); |
| |
| for (unsigned int i=0; i < bufferLength; i++) |
| Write( bufferAddress + i, bufferString[i]); |
| |
| Write(0xEF, bufferLength); |
| } |
| |
| ClockCycle TED::GetClockCount() |
| { |
| return CycleCounter; |
| } |
| |
| void TED::ChangeMemBankSetup(bool romoff) |
| { |
| if (romoff) { |
| mem_8000_bfff = actram + (0x8000 & RAMMask); |
| mem_fc00_fcff = mem_c000_ffff = actram + (0xC000 & RAMMask); |
| } else { |
| mem_8000_bfff = actromlo; |
| mem_c000_ffff = actromhi; |
| mem_fc00_fcff = &(RomHi[0][0]); |
| } |
| } |
| |
| unsigned char TED::Read(unsigned int addr) |
| { |
| switch ( addr & 0xF000 ) { |
| case 0x0000: |
| switch ( addr & 0xFFFF ) { |
| case 0: |
| return prddr; |
| case 1: |
| { |
| unsigned char retval = |
| ( |
| //ReadBus()& |
| 0xC0) |
| //|(tap->ReadCSTIn(CycleCounter)&0x10) |
| ; |
| return (prp&prddr)|(retval&~prddr); |
| } |
| default: |
| return actram[addr&0xFFFF]; |
| } |
| break; |
| case 0x1000: |
| case 0x2000: |
| case 0x3000: |
| return actram[addr&0xFFFF]; |
| case 0x4000: |
| case 0x5000: |
| case 0x6000: |
| case 0x7000: |
| return actram[addr&RAMMask]; |
| case 0x8000: |
| case 0x9000: |
| case 0xA000: |
| case 0xB000: |
| return mem_8000_bfff[addr&0x3FFF]; |
| case 0xC000: |
| case 0xD000: |
| case 0xE000: |
| return mem_c000_ffff[addr&0x3FFF]; |
| case 0xF000: |
| switch ( addr >> 8 ) { |
| case 0xFF: |
| switch (addr) { |
| case 0xFF00 : return timer1&0xFF; |
| case 0xFF01 : return timer1>>8; |
| case 0xFF02 : return timer2&0xFF; |
| case 0xFF03 : return timer2>>8; |
| case 0xFF04 : return timer3&0xFF; |
| case 0xFF05 : return timer3>>8; |
| case 0xFF06 : return Ram[0xFF06]; |
| case 0xFF07 : return Ram[0xFF07]; |
| case 0xFF08 : |
| #if 0 |
| if (joyemu) |
| return keys->feedjoy(Ram[0xFF08])&(keys->feedkey(Ram[0xFD30])); |
| else |
| return keys->feedkey(Ram[0xFD30]); |
| #else |
| return 0xFF; |
| #endif |
| case 0xFF09 : return Ram[0xFF09]|(0x25); |
| case 0xFF0A : return Ram[0xFF0A]|(0xA0); |
| case 0xFF0B : return irqline & 0xFF; |
| case 0xFF0C : return ((crsrpos>>8)&0x03)|0xFC; |
| case 0xFF0D : return crsrpos&0xFF; |
| case 0xFF0E : |
| case 0xFF0F : |
| case 0xFF10 : |
| case 0xFF11 : |
| case 0xFF12 : |
| case 0xFF13 : |
| case 0xFF14 : |
| return Ram[addr]; |
| case 0xFF15 : return ecol[0]|0x80; // The highest bit is not used and so always 1 |
| case 0xFF16 : return ecol[1]|0x80; // A few games (Rockman) used it... |
| case 0xFF17 : return ecol[2]|0x80; |
| case 0xFF18 : return ecol[3]|0x80; |
| case 0xFF19 : return (framecol&0xFF)|0x80; |
| case 0xFF1A : return (CharacterPositionReload>>8)&0xFF; |
| case 0xFF1B : return CharacterPositionReload&0xFF; |
| case 0xFF1C : return (beamy>>8)|0xFE; |
| case 0xFF1D : return beamy&0xFF; /// 1-8. bit of the rasterline counter |
| case 0xFF1E : return ((98+beamx)<<1)%228; // raster column |
| case 0xFF1F : return 0x80|(crsrphase<<3)|VertSubCount; |
| default: |
| return mem_c000_ffff[addr&0x3FFF]; |
| } |
| break; |
| case 0xFE: |
| //return tcbmbus->Read(addr); |
| //return 0xFE; |
| return protectedPlayerMemory[addr & 0xfff]; |
| case 0xFD: |
| switch (addr>>4) { |
| case 0xFD0: // RS232 |
| return 0xFD; |
| case 0xFD1: // User port, PIO & 256 RAM expansion |
| //return (tap->IsButtonPressed()<<2)^0xFF; |
| return 0xFF; |
| case 0xFD2: // Speech hardware |
| case 0xFD4: // SID Card |
| case 0xFD5: |
| if (sidCard) { |
| return sidCard->read(addr & 0x1f); |
| } |
| return 0xFD; |
| case 0xFD3: |
| return Ram[0xFD30]; |
| } |
| return 0xFD; |
| case 0xFC: |
| return mem_fc00_fcff[addr&0x3FFF]; |
| default: |
| return mem_c000_ffff[addr&0x3FFF]; |
| } |
| } |
| //fprintf(stderr,"Unhandled read %04X\n", addr); |
| return 0; |
| } |
| |
| void TED::UpdateSerialState(unsigned char portVal) |
| { |
| static unsigned char prevVal = 0xC0; |
| |
| //if ((prevVal ^ portVal)&8) |
| // tap->SetTapeMotor(CycleCounter, portVal&8); |
| |
| prevVal = portVal; |
| } |
| |
| void TED::Write(unsigned int addr, unsigned char value) |
| { |
| switch (addr&0xF000) { |
| case 0x0000: |
| switch ( addr & 0xFFFF ) { |
| case 0: |
| //fprintf(stderr,"$00 write: %02X\n", value); |
| prddr = value & 0xDF; |
| UpdateSerialState(prddr&~prp); |
| return; |
| case 1: |
| //fprintf(stderr,"$01 write: %02X\n", value); |
| prp = value; |
| UpdateSerialState(prddr&~prp); |
| return; |
| default: |
| actram[addr&0xFFFF] = value; |
| } |
| return; |
| case 0x1000: |
| case 0x2000: |
| case 0x3000: |
| actram[addr&0xFFFF] = value; |
| return; |
| case 0xD000: |
| if (sidCard) { |
| sidCard->write(addr & 0x1f, value); |
| sidCard->setFrequency(1); |
| } |
| case 0x4000: |
| case 0x5000: |
| case 0x6000: |
| case 0x7000: |
| case 0x8000: |
| case 0x9000: |
| case 0xA000: |
| case 0xB000: |
| case 0xC000: |
| case 0xE000: |
| actram[addr&RAMMask] = value; |
| return; |
| case 0xF000: |
| switch ( addr >> 8 ) { |
| case 0xFF: |
| switch (addr) { |
| case 0xFF00 : |
| t1on=false; // Timer1 disabled |
| t1start=(t1start & 0xFF00)|value; |
| timer1=(timer1 & 0xFF00)|value; |
| return; |
| case 0xFF01 : |
| t1on=true; // Timer1 enabled |
| t1start=(t1start & 0xFF)|(value<<8); |
| timer1=(timer1 & 0x00FF)|(value<<8); |
| return; |
| case 0xFF02 : |
| t2on=false; // Timer2 disabled |
| timer2=(timer2 & 0xFF00)|value; |
| return; |
| case 0xFF03 : |
| t2on=true; // Timer2 enabled |
| timer2=(timer2&0x00FF)|(value<<8); |
| return; |
| case 0xFF04 : |
| t3on=false; // Timer3 disabled |
| timer3=(timer3&0xFF00)|value; |
| return; |
| case 0xFF05 : |
| t3on=true; // Timer3 enabled |
| timer3=(timer3&0x00FF)|(value<<8); |
| return; |
| case 0xFF06 : |
| Ram[0xFF06]=value; |
| // get vertical offset of screen when smooth scroll |
| vshift = value&0x07; |
| // Check if screen is turned on |
| if (value&0x10 && beamy == 0 && !AttribFetch) { |
| AttribFetch = true; |
| VertSubCount = 7; |
| if (vshift != (beamy&7)) { |
| // FIXME: this is actually delayed by one cycle |
| if (beamx>4 && beamx<84) |
| ClockingState = TSS; |
| } |
| } |
| if ( (Ram[0xFF06] ^ value) & 0x1F) { |
| if (AttribFetch) { |
| if (vshift == (beamy&7)) { |
| BadLine |= 1; |
| if (beamx>=3 && beamx<89) { |
| unsigned char idleread = Read((cpuptr->getPC()+1)&0xFFFF); |
| unsigned int delay = (BadLine & 2) ? 0 : (beamx - 1) >> 1; |
| unsigned int invalidcount = (delay > 3) ? 3 : delay; |
| unsigned int invalidpos = delay - invalidcount; |
| invalidcount = (invalidcount < 40-invalidpos) ? invalidcount : 40-invalidpos; |
| unsigned int newdmapos = (invalidpos+invalidcount < 40) ? invalidpos+invalidcount : 40; |
| unsigned int newdmacount = 40 - newdmapos ; |
| unsigned int oldcount = 40 - newdmacount - invalidcount; |
| memcpy( DMAbuf, clrbuf, oldcount); |
| memset( DMAbuf+oldcount, idleread, invalidcount); |
| memcpy( DMAbuf+oldcount+invalidcount, VideoBase + CharacterCount + oldcount |
| + invalidcount, newdmacount); |
| //DoDMA(tmpClrbuf + delay, 0); |
| ClockingState = THALT1; |
| } else if (beamx<111 && beamx>=89) { |
| // FIXME this breaks on FF1E writes |
| // swap DMA fetch pointers for colour DMA... |
| if (!(BadLine & 1) && beamx < 94) { |
| unsigned char *tmpbuf = clrbuf; |
| clrbuf = tmpClrbuf; |
| tmpClrbuf = tmpbuf; |
| } |
| //BadLine |= 1; |
| } |
| } else if (BadLine & 1 /*beamx>=91*/) { |
| if (beamx>=94) { |
| BadLine &= ~1; |
| } else if (beamx >= 91) { |
| unsigned char *tmpbuf = clrbuf; |
| clrbuf = tmpClrbuf; |
| tmpClrbuf = tmpbuf; |
| BadLine &= ~1; |
| } |
| } |
| } |
| } |
| // Delayed DMA? |
| // check for flat screen (23 rows) |
| fltscr = !(value&0x08); |
| // check for extended mode |
| ecmode=value&EXTCOLOR; |
| if (ecmode) { |
| tmp=(0xF800)&RAMMask; |
| scrattr|=EXTCOLOR; |
| } else { |
| tmp=(0xFC00)&RAMMask; |
| scrattr&=~EXTCOLOR; |
| } |
| charrambank=Ram+((Ram[0xFF13]<<8)&tmp); |
| charrombank=&(RomHi[0][((Ram[0xFF13] & 0x3C)<<8)&tmp]); |
| // check for graphics mode (5th b14it) |
| scrattr=(scrattr&~GRAPHMODE)|(value&GRAPHMODE); |
| return; |
| case 0xFF07 : |
| Ram[0xFF07]=value; |
| // check for narrow screen (38 columns) |
| nrwscr=value&0x08; |
| // get horizontal offset of screen when smooth scroll |
| hshift=value&0x07; |
| // check for reversed mode |
| rvsmode=value&0x80; |
| if (rvsmode) { |
| tmp=(0xF800)&RAMMask; |
| scrattr|=REVERSE; |
| } else { |
| tmp=(0xFC00)&RAMMask; |
| scrattr&=~REVERSE; |
| } |
| charrombank=&(RomHi[0][((Ram[0xFF13] & 0x3C)<<8)&tmp]); |
| charrambank=Ram+((Ram[0xFF13]<<8)&tmp); |
| cset = charrom ? charrombank : charrambank; |
| // check for multicolor mode |
| scrattr=(scrattr&~MULTICOLOR)|(value&0x10); |
| return; |
| case 0xFF08 : |
| Ram[0xFF08] = value; |
| return; |
| case 0xFF09 : |
| // clear the interrupt requester bits |
| // by writing 1 into them (!!) |
| Ram[0xFF09]=(Ram[0xFF09]&0x7F)&(~value); |
| return; |
| case 0xFF0A : |
| { |
| Ram[0xFF0A]=value; |
| // change the raster irq line |
| unsigned int newirqline = (irqline&0xFF)|((value&0x01)<<8); |
| if (newirqline != irqline) { |
| if (beamy == newirqline) |
| Ram[0xFF0A]&0x02 ? Ram[0xFF09]|=0x82 : Ram[0xFF09]|=0x02; |
| irqline = newirqline; |
| } |
| } |
| return; |
| case 0xFF0B : |
| { |
| Ram[0xFF0B]=value; |
| unsigned int newirqline = value|(irqline&0x0100); |
| if (newirqline != irqline) { |
| if (beamy == newirqline) |
| Ram[0xFF0A]&0x02 ? Ram[0xFF09]|=0x82 : Ram[0xFF09]|=0x02; |
| irqline = newirqline; |
| } |
| } |
| return; |
| case 0xFF0C : |
| crsrpos=((value<<8)|(crsrpos&0xFF))&0x3FF; |
| return; |
| case 0xFF0D : |
| crsrpos=value|(crsrpos&0xFF00); |
| return; |
| case 0xFF0E : |
| writeSoundReg(0, value); |
| Ram[0xFF0E]=value; |
| return; |
| case 0xFF0F : |
| writeSoundReg(1, value); |
| Ram[0xFF0F]=value; |
| return; |
| case 0xFF10 : |
| writeSoundReg(2, value & 3); |
| Ram[0xFF10]=value; |
| return; |
| case 0xFF11 : |
| Ram[0xFF11]=value; |
| writeSoundReg(3, value); |
| return; |
| case 0xFF12: |
| grbank=Ram+((value&0x38)<<10); |
| if ((value ^ Ram[0xFF12]) & 3) |
| writeSoundReg(4, value & 3); |
| // if the 2nd bit is set the chars are read from ROM |
| charrom=(value&0x04)>0; |
| if (charrom && Ram[0xFF13]<0x80) |
| scrattr|=ILLEGAL; |
| else { |
| scrattr&=~ILLEGAL; |
| cset = (charrom) ? charrombank : charrambank; |
| } |
| Ram[0xFF12]=value; |
| return; |
| case 0xFF13 : |
| // the 0th bit is not writable, it indicates if the ROMs are on |
| Ram[0xFF13]=(value&0xFE)|(Ram[0xFF13]&0x01); |
| // bit 1 is the fast/slow mode switch |
| fastmode = !(value&0x02); |
| (ecmode || rvsmode) ? tmp=(0xF800)&RAMMask : tmp=(0xFC00)&RAMMask; |
| charbank = ((value)<<8)&tmp; |
| charrambank=Ram+charbank; |
| charrombank=&(RomHi[0][charbank & 0x3C00]); |
| if (charrom && value<0x80) |
| scrattr|=ILLEGAL; |
| else { |
| scrattr&=~ILLEGAL; |
| (charrom) ? cset = charrombank : cset = charrambank; |
| } |
| return; |
| case 0xFF14 : |
| Ram[0xFF14]=value; |
| VideoBase=colorbank=Ram+(((value&0xF8)<<8)&RAMMask); |
| return; |
| case 0xFF15 : |
| ecol[0]=bmmcol[0]=mcol[0]=value&0x7F; |
| return; |
| case 0xFF16 : |
| ecol[1]=bmmcol[3]=mcol[1]=value&0x7F; |
| return; |
| case 0xFF17 : |
| ecol[2]=mcol[2]=value&0x7F; |
| return; |
| case 0xFF18 : |
| ecol[3]=value&0x7F; |
| return; |
| case 0xFF19 : |
| value &= 0x7F; |
| framecol=(value<<24)|(value<<16)|(value<<8)|value; |
| return; |
| case 0xFF1A : |
| CharacterPositionReload = (CharacterPositionReload & 0xFF) | ((value&3)<<8); |
| return; |
| case 0xFF1B : |
| CharacterPositionReload = (CharacterPositionReload & 0x300) | value; |
| return; |
| case 0xFF1C : |
| beamy=((value&0x01)<<8)|(beamy&0xFF); |
| return; |
| case 0xFF1D : |
| beamy=(beamy&0x0100)|value; |
| return; |
| case 0xFF1E : |
| { |
| unsigned int low_x = beamx&1; |
| // lowest 2 bits are not writable |
| // inverted value must be written |
| unsigned int new_beamx=((~value))&0xFC; |
| new_beamx >>= 1; |
| new_beamx>=98 ? new_beamx -= 98 : new_beamx += 16; |
| // writes are aligned to single clock cycles |
| if (low_x) { |
| aligned_write = true; |
| aw_addr_ptr = (unsigned char*)(&beamx); |
| aw_value = new_beamx; |
| } else { |
| beamx = new_beamx; |
| } |
| } |
| return; |
| case 0xFF1F : |
| VertSubCount=value&0x07; |
| crsrphase=(value&0x78)>>3; |
| return; |
| case 0xFF3E : |
| Ram[0xFF13]|=0x01; |
| RAMenable=false; |
| ChangeMemBankSetup(RAMenable); |
| return; |
| case 0xFF3F : |
| Ram[0xFF13]&=0xFE; |
| RAMenable=true; |
| ChangeMemBankSetup(RAMenable); |
| return; |
| } |
| actram[addr&RAMMask] = value; |
| return; |
| case 0xFE: |
| //tcbmbus->Write(addr,value); |
| return; |
| case 0xFD: |
| switch (addr>>4) { |
| case 0xFD0: // RS232 |
| case 0xFD1: // User port, PIO & 256 RAM expansion |
| case 0xFD2: // Speech hardware |
| return; |
| case 0xFD3: |
| Ram[0xFD30] = value; |
| return; |
| case 0xFD4: // SID Card |
| case 0xFD5: |
| if (sidCard) { |
| sidCard->setFrequency(0); |
| sidCard->write(addr & 0x1f, value); |
| } |
| return; |
| case 0xFDD: |
| actromlo=&(RomLo[addr&0x03][0]); |
| actromhi=&(RomHi[(addr&0x0c)>>2][0]); |
| return; |
| } |
| return; |
| default: |
| actram[addr&RAMMask] = value; |
| return; |
| } |
| } |
| return; |
| } |
| |
| void TED::dump(void *img) |
| { |
| // this is ugly :-P |
| fwrite(Ram,RAMSIZE,1,(FILE *) img); |
| fwrite(&RAMenable,sizeof(RAMenable),1,(FILE *) img); |
| fwrite(&t1start,sizeof(t1start),1, (FILE *) img); |
| fwrite(&t1on,sizeof(t1on),1, (FILE *) img); |
| fwrite(&t2on,sizeof(t2on),1, (FILE *) img); |
| fwrite(&t3on,sizeof(t3on),1, (FILE *) img); |
| fwrite(&timer1,sizeof(timer1),1, (FILE *) img); |
| fwrite(&timer2,sizeof(timer2),1, (FILE *) img); |
| fwrite(&timer3,sizeof(timer3),1, (FILE *) img); |
| fwrite(&beamx,sizeof(beamx),1, (FILE *) img); |
| fwrite(&beamy,sizeof(beamy),1, (FILE *) img); |
| //fwrite(&x,sizeof(x),1, (FILE *) img); |
| fwrite(&irqline,sizeof(irqline),1, (FILE *) img); |
| fwrite(&crsrpos,sizeof(crsrpos),1, (FILE *) img); |
| fwrite(&scrattr,sizeof(scrattr),1, (FILE *) img); |
| fwrite(&tmp,sizeof(tmp),1, (FILE *) img); |
| fwrite(&nrwscr,sizeof(nrwscr),1, (FILE *) img); |
| fwrite(&hshift,sizeof(hshift),1, (FILE *) img); |
| fwrite(&vshift,sizeof(vshift),1, (FILE *) img); |
| fwrite(&fltscr,sizeof(fltscr),1, (FILE *) img); |
| fwrite(&mcol,sizeof(mcol),1, (FILE *) img); |
| fwrite(chrbuf,40,1, (FILE *) img); |
| fwrite(clrbuf,40,1, (FILE *) img); |
| fwrite(&charrom,sizeof(charrom),1, (FILE *) img); |
| fwrite(&charbank,sizeof(charbank),1, (FILE *) img); |
| // fwrite(&TEDfreq1,sizeof(TEDfreq1),1, (FILE *) img); |
| // fwrite(&TEDfreq2,sizeof(TEDfreq2),1, (FILE *) img); |
| // fwrite(&TEDVolume,sizeof(TEDVolume),1, (FILE *) img); |
| // fwrite(&TEDDA,sizeof(TEDDA),1, (FILE *) img); |
| fwrite(&framecol,sizeof(framecol),1, (FILE *) img); |
| } |
| |
| void TED::memin(void *img) |
| { |
| |
| // this is ugly :-P |
| fread(Ram,RAMSIZE,1,(FILE *) img); |
| |
| fread(&RAMenable,sizeof(RAMenable),1,(FILE *) img); |
| fread(&t1start,sizeof(t1start),1, (FILE *) img); |
| fread(&t1on,sizeof(t1on),1, (FILE *) img); |
| fread(&t2on,sizeof(t2on),1, (FILE *) img); |
| fread(&t3on,sizeof(t3on),1, (FILE *) img); |
| fread(&timer1,sizeof(timer1),1, (FILE *) img); |
| fread(&timer2,sizeof(timer2),1, (FILE *) img); |
| fread(&timer3,sizeof(timer3),1, (FILE *) img); |
| fread(&beamx,sizeof(beamx),1, (FILE *) img); |
| fread(&beamy,sizeof(beamy),1, (FILE *) img); |
| //fread(&x,sizeof(x),1, (FILE *) img); |
| fread(&irqline,sizeof(irqline),1, (FILE *) img); |
| fread(&crsrpos,sizeof(crsrpos),1, (FILE *) img); |
| fread(&scrattr,sizeof(scrattr),1, (FILE *) img); |
| fread(&tmp,sizeof(tmp),1, (FILE *) img); |
| fread(&nrwscr,sizeof(nrwscr),1, (FILE *) img); |
| fread(&hshift,sizeof(hshift),1, (FILE *) img); |
| fread(&vshift,sizeof(vshift),1, (FILE *) img); |
| fread(&fltscr,sizeof(fltscr),1, (FILE *) img); |
| fread(&mcol,sizeof(mcol),1, (FILE *) img); |
| fread(chrbuf,40,1, (FILE *) img); |
| fread(clrbuf,40,1, (FILE *) img); |
| fread(&charrom,sizeof(charrom),1, (FILE *) img); |
| fread(&charbank,sizeof(charbank),1, (FILE *) img); |
| // fread(&TEDfreq1,sizeof(TEDfreq1),1, (FILE *) img); |
| // fread(&TEDfreq2,sizeof(TEDfreq2),1, (FILE *) img); |
| // fread(&TEDVolume,sizeof(TEDVolume),1, (FILE *) img); |
| // fread(&TEDDA,sizeof(TEDDA),1, (FILE *) img); |
| fread(&framecol,sizeof(framecol),1, (FILE *) img); |
| |
| for (int i=0; i<5; i++) |
| writeSoundReg(i, Ram[0xFF0E + i]); |
| beamy=0; |
| beamx=0; |
| scrptr=&(screen[0]); |
| charrambank=Ram+charbank; |
| charrombank=&(RomHi[0][charbank & 0x3C00]); |
| (charrom) ? cset = charrombank : cset = charrambank; |
| |
| } |
| |
| // when multi and extended color modes are all on the screen is blank |
| inline void TED::mcec() |
| { |
| memset( scrptr, 0, 8); |
| } |
| |
| // renders hires text with reverse (128 chars) |
| inline void TED::hi_text() |
| { |
| unsigned char chr; |
| unsigned char charcol; |
| unsigned char mask; |
| unsigned char *wbuffer = scrptr + hshift; |
| |
| // get the actual physical character column |
| charcol=clrbuf[x]; |
| chr=chrbuf[x]; |
| |
| if ((charcol)&0x80 && !crsrblinkon) |
| mask = 00; |
| else |
| mask = cset[((chr&0x7F)<<3)|VertSubCount]; |
| |
| if (chr&0x80) |
| mask ^= 0xFF; |
| if (crsrpos==((CharacterPosition+x)&0x3FF) && crsrblinkon ) |
| mask ^= 0xFF; |
| |
| wbuffer[0] = (mask & 0x80) ? charcol : mcol[0]; |
| wbuffer[1] = (mask & 0x40) ? charcol : mcol[0]; |
| wbuffer[2] = (mask & 0x20) ? charcol : mcol[0]; |
| wbuffer[3] = (mask & 0x10) ? charcol : mcol[0]; |
| wbuffer[4] = (mask & 0x08) ? charcol : mcol[0]; |
| wbuffer[5] = (mask & 0x04) ? charcol : mcol[0]; |
| wbuffer[6] = (mask & 0x02) ? charcol : mcol[0]; |
| wbuffer[7] = (mask & 0x01) ? charcol : mcol[0]; |
| } |
| |
| // renders text without the reverse (all 256 chars) |
| inline void TED::rv_text() |
| { |
| unsigned char chr; |
| unsigned char charcol; |
| unsigned char mask; |
| unsigned char *wbuffer = scrptr + hshift; |
| |
| // get the actual physical character column |
| charcol=clrbuf[x]; |
| chr=chrbuf[x]; |
| |
| if ((charcol)&0x80 && !crsrblinkon) |
| mask = 00; |
| else |
| mask = cset[(chr<<3)|VertSubCount]; |
| |
| if (crsrpos==((CharacterPosition+x)&0x3FF) && crsrblinkon ) |
| mask ^= 0xFF; |
| |
| wbuffer[0] = (mask & 0x80) ? charcol : mcol[0]; |
| wbuffer[1] = (mask & 0x40) ? charcol : mcol[0]; |
| wbuffer[2] = (mask & 0x20) ? charcol : mcol[0]; |
| wbuffer[3] = (mask & 0x10) ? charcol : mcol[0]; |
| wbuffer[4] = (mask & 0x08) ? charcol : mcol[0]; |
| wbuffer[5] = (mask & 0x04) ? charcol : mcol[0]; |
| wbuffer[6] = (mask & 0x02) ? charcol : mcol[0]; |
| wbuffer[7] = (mask & 0x01) ? charcol : mcol[0]; |
| } |
| |
| // renders extended color text |
| inline void TED::ec_text() |
| { |
| unsigned char charcol; |
| unsigned char chr; |
| unsigned char mask; |
| unsigned char *wbuffer = scrptr + hshift; |
| |
| // get the actual physical character column |
| charcol = clrbuf[x]; |
| chr = chrbuf[x]; |
| |
| mask = cset[ ((chr&0x3F)<<3)|VertSubCount ]; |
| |
| chr = (chr&0xC0)>>6; |
| |
| wbuffer[0] = (mask & 0x80) ? charcol : ecol[chr]; |
| wbuffer[1] = (mask & 0x40) ? charcol : ecol[chr]; |
| wbuffer[2] = (mask & 0x20) ? charcol : ecol[chr]; |
| wbuffer[3] = (mask & 0x10) ? charcol : ecol[chr]; |
| wbuffer[4] = (mask & 0x08) ? charcol : ecol[chr]; |
| wbuffer[5] = (mask & 0x04) ? charcol : ecol[chr]; |
| wbuffer[6] = (mask & 0x02) ? charcol : ecol[chr]; |
| wbuffer[7] = (mask & 0x01) ? charcol : ecol[chr]; |
| } |
| |
| // renders multicolor text |
| inline void TED::mc_text_rvs() |
| { |
| unsigned char chr=chrbuf[x]; |
| unsigned char charcol=clrbuf[x]; |
| unsigned char *wbuffer = scrptr + hshift; |
| unsigned char mask; |
| |
| mask = cset[ (chr<<3)|VertSubCount ]; |
| |
| if (charcol&0x08) { // if character is multicolored |
| |
| mcol[3]=charcol&0xF7; |
| |
| wbuffer[0] = wbuffer[1] = mcol[ (mask & 0xC0) >> 6 ]; |
| wbuffer[2] = wbuffer[3] = mcol[ (mask & 0x30) >> 4 ]; |
| wbuffer[4] = wbuffer[5] = mcol[ (mask & 0x0C) >> 2 ]; |
| wbuffer[6] = wbuffer[7] = mcol[ mask & 0x03 ]; |
| |
| } else { // this is a normally colored character |
| |
| wbuffer[0] = (mask & 0x80) ? charcol : mcol[0]; |
| wbuffer[1] = (mask & 0x40) ? charcol : mcol[0]; |
| wbuffer[2] = (mask & 0x20) ? charcol : mcol[0]; |
| wbuffer[3] = (mask & 0x10) ? charcol : mcol[0]; |
| wbuffer[4] = (mask & 0x08) ? charcol : mcol[0]; |
| wbuffer[5] = (mask & 0x04) ? charcol : mcol[0]; |
| wbuffer[6] = (mask & 0x02) ? charcol : mcol[0]; |
| wbuffer[7] = (mask & 0x01) ? charcol : mcol[0]; |
| } |
| } |
| |
| // renders multicolor text with reverse bit set |
| inline void TED::mc_text() |
| { |
| unsigned char charcol=clrbuf[x]; |
| unsigned char chr=chrbuf[x]&0x7F; |
| unsigned char *wbuffer = scrptr + hshift; |
| unsigned char mask; |
| |
| mask = cset[ (chr<<3)|VertSubCount ]; |
| |
| if ((charcol)&0x08) { // if character is multicolored |
| |
| mcol[3]=(charcol)&0xF7; |
| |
| wbuffer[0] = wbuffer[1] = mcol[ (mask & 0xC0) >> 6 ]; |
| wbuffer[2] = wbuffer[3] = mcol[ (mask & 0x30) >> 4 ]; |
| wbuffer[4] = wbuffer[5] = mcol[ (mask & 0x0C) >> 2 ]; |
| wbuffer[6] = wbuffer[7] = mcol[ mask & 0x03 ]; |
| |
| } else { // this is a normally colored character |
| |
| wbuffer[0] = (mask & 0x80) ? charcol : mcol[0]; |
| wbuffer[1] = (mask & 0x40) ? charcol : mcol[0]; |
| wbuffer[2] = (mask & 0x20) ? charcol : mcol[0]; |
| wbuffer[3] = (mask & 0x10) ? charcol : mcol[0]; |
| wbuffer[4] = (mask & 0x08) ? charcol : mcol[0]; |
| wbuffer[5] = (mask & 0x04) ? charcol : mcol[0]; |
| wbuffer[6] = (mask & 0x02) ? charcol : mcol[0]; |
| wbuffer[7] = (mask & 0x01) ? charcol : mcol[0]; |
| } |
| } |
| |
| // renders hires bitmap graphics |
| inline void TED::hi_bitmap() |
| { |
| unsigned char mask; |
| unsigned char *wbuffer = scrptr + hshift; |
| // get the actual color attributes |
| hcol[0]=(chrbuf[x]&0x0F)|(clrbuf[x]&0x70); |
| hcol[1]=((chrbuf[x]&0xF0)>>4)|((clrbuf[x]&0x07)<<4); |
| |
| mask = grbank[ (((CharacterPosition+x)<<3)&0x1FFF)|VertSubCount ]; |
| |
| wbuffer[0] = (mask & 0x80) ? hcol[1] : hcol[0]; |
| wbuffer[1] = (mask & 0x40) ? hcol[1] : hcol[0]; |
| wbuffer[2] = (mask & 0x20) ? hcol[1] : hcol[0]; |
| wbuffer[3] = (mask & 0x10) ? hcol[1] : hcol[0]; |
| wbuffer[4] = (mask & 0x08) ? hcol[1] : hcol[0]; |
| wbuffer[5] = (mask & 0x04) ? hcol[1] : hcol[0]; |
| wbuffer[6] = (mask & 0x02) ? hcol[1] : hcol[0]; |
| wbuffer[7] = (mask & 0x01) ? hcol[1] : hcol[0]; |
| |
| } |
| |
| // renders multicolor bitmap graphics |
| inline void TED::mc_bitmap() |
| { |
| unsigned char mask; |
| unsigned char *wbuffer = scrptr + hshift; |
| // get the actual color attributes |
| bmmcol[1]=((chrbuf[x]&0xF0)>>4)|((clrbuf[x]&0x07)<<4); |
| bmmcol[2]=(chrbuf[x]&0x0F)|(clrbuf[x]&0x70); |
| |
| mask = grbank[ (((CharacterPosition+x)<<3)&0x1FFF)+VertSubCount ]; |
| |
| wbuffer[0]= wbuffer[1] = bmmcol[ (mask & 0xC0) >> 6 ]; |
| wbuffer[2]= wbuffer[3] = bmmcol[ (mask & 0x30) >> 4 ]; |
| wbuffer[4]= wbuffer[5] = bmmcol[ (mask & 0x0C) >> 2 ]; |
| wbuffer[6]= wbuffer[7] = bmmcol[ mask & 0x03 ]; |
| } |
| |
| // "illegal" mode: when $FF13 points to an illegal ROM address |
| // the current data on the bus is displayed |
| inline void TED::illegalbank() |
| { |
| unsigned char chr = chrbuf[x]; |
| unsigned char charcol = clrbuf[x]; |
| unsigned char mask; |
| unsigned char *wbuffer = scrptr + hshift; |
| |
| if (charcol&0x80 && crsrblinkon) |
| mask = 00; |
| else { |
| if (BadLine==1) |
| mask = clrbuf[x]; |
| else if (BadLine==2) |
| mask = chrbuf[x]; |
| else |
| mask = Read(cpuptr->getPC()); |
| } |
| |
| if (chr&0x80) |
| mask ^= 0xFF; |
| if (crsrpos==((CharacterPosition+x)&0x3FF) && crsrblinkon) |
| mask ^= 0xFF; |
| |
| wbuffer[0] = (mask & 0x80) ? charcol : mcol[0]; |
| wbuffer[1] = (mask & 0x40) ? charcol : mcol[0]; |
| wbuffer[2] = (mask & 0x20) ? charcol : mcol[0]; |
| wbuffer[3] = (mask & 0x10) ? charcol : mcol[0]; |
| wbuffer[4] = (mask & 0x08) ? charcol : mcol[0]; |
| wbuffer[5] = (mask & 0x04) ? charcol : mcol[0]; |
| wbuffer[6] = (mask & 0x02) ? charcol : mcol[0]; |
| wbuffer[7] = (mask & 0x01) ? charcol : mcol[0]; |
| } |
| |
| inline void TED::DoDMA( unsigned char *Buf, unsigned int Offset ) |
| { |
| if ( CharacterCount>=0x03D8 ) { |
| memcpy( Buf, VideoBase + CharacterCount + Offset, 0x400 - CharacterCount); |
| memcpy( Buf + 0x400 - CharacterCount, VideoBase + Offset, (CharacterCount + 40)&0x03FF); |
| } else { |
| memcpy( Buf, VideoBase + CharacterCount + Offset, 40); |
| } |
| } |
| |
| // main loop of the whole emulation as the TED feeds the CPU with clock cycles |
| void TED::ted_process(short *buffer, unsigned int count) |
| { |
| do { |
| switch(++beamx) { |
| |
| default: |
| break; |
| |
| case 2: |
| if (VertSubActive) |
| VertSubCount = (VertSubCount+1)&7; |
| break; |
| |
| case 3: |
| if (AttribFetch && beamy==0) { |
| VertSubCount = 7; |
| } |
| break; |
| |
| case 4: |
| if (AttribFetch) { |
| BadLine |= ((vshift)&7) == (beamy&7); |
| if ( BadLine ) { |
| ClockingState = THALT1; |
| } else |
| ClockingState = TSS; |
| if (beamy==203) { |
| AttribFetch = false; |
| if (!(BadLine & 2)) ClockingState = TSS; |
| } |
| } |
| break; |
| |
| case 8: |
| HBlanking = false; |
| break; |
| |
| case 10: |
| if (VertSubActive) |
| CharacterPosition = CharacterPositionReload; |
| break; |
| |
| case 16: |
| if (ScreenOn) { |
| SideBorderFlipFlop = true; |
| memset( scrptr, mcol[0], hshift); |
| if (nrwscr) |
| CharacterWindow = true; |
| x = 0; |
| } |
| if (BadLine & 1) |
| DoDMA(tmpClrbuf, 0); |
| if (BadLine & 2) |
| DoDMA(chrbuf, (BadLine & 1) ? 0 : 0x400); |
| break; |
| |
| case 18: |
| if (ScreenOn && !nrwscr) { |
| CharacterWindow = true; |
| } |
| break; |
| |
| case 89: |
| if (/*VertSubActive &&*/ VertSubCount == 6) |
| CharacterCount = (CharacterCount + 40)&0x3FF; |
| break; |
| |
| case 90: |
| if ( VertSubActive && VertSubCount == 7 ) |
| CharacterPositionReload = (CharacterPosition + 40)&0x3FF; |
| break; |
| |
| case 91: |
| ClockingState = TRFSH; |
| break; |
| |
| case 94: |
| if (ScreenOn && !nrwscr) |
| SideBorderFlipFlop = CharacterWindow = false; |
| break; |
| |
| case 96: |
| if (ScreenOn && nrwscr) |
| SideBorderFlipFlop = CharacterWindow = false; |
| // FIXME this breaks on FF1E writes |
| if (BadLine & 1) { |
| // swap DMA fetch pointers for colour DMA... |
| unsigned char *tmpbuf = clrbuf; |
| clrbuf = tmpClrbuf; |
| tmpClrbuf = tmpbuf; |
| } |
| break; |
| |
| case 111: |
| if ((BadLine&1)) { |
| BadLine = 2; |
| VertSubActive = true; |
| } else if (BadLine&2) {// in the second bad line, we're finished... |
| BadLine &= ~2; |
| } |
| break; |
| |
| case 102: |
| ClockingState = fastmode ? TDS : TSS; |
| break; |
| |
| case 104: |
| HBlanking = true; |
| break; |
| |
| case 107: // HSYNC start |
| break; |
| |
| case 256: |
| case 128: |
| beamx = 15; |
| break; |
| case 114: // HSYNC end |
| beamx=0; |
| // the beam reached a new line |
| TVScanLineCounter += 1; |
| if ( TVScanLineCounter >= 340 ) { |
| TVScanLineCounter = 0; |
| scrptr=screen; |
| // render_ok=true; |
| } |
| switch (++beamy) { |
| |
| case 4: |
| if (!fltscr) ScreenOn = AttribFetch; |
| break; |
| |
| case 8: |
| if (fltscr) ScreenOn = AttribFetch; |
| break; |
| |
| case 200: |
| if (fltscr) ScreenOn = false; |
| break; |
| |
| case 204: |
| if (!fltscr) ScreenOn = false; |
| break; |
| |
| case 205: |
| CharacterCount = 0; |
| // cursor phase counter in TED register $1F |
| VertSubActive = false; |
| if ((++crsrphase&0x0F) == 0x0F) |
| crsrblinkon ^= 1; |
| break; |
| |
| case 251: |
| VBlanking = true; |
| break; |
| |
| case 261: // Vertical retrace |
| // frame ready... |
| //render_ok=true; |
| // reset screen pointer ("TV" electron beam) |
| scrptr=screen; |
| TVScanLineCounter = 0; |
| break; |
| |
| case 271: |
| VBlanking = false; |
| break; |
| |
| case 512: |
| case 312: |
| beamy = 0; |
| CharacterPosition = CharacterPositionReload = 0; |
| AttribFetch = (Ram[0xFF06]&0x10) != 0; |
| } |
| // is there raster interrupt? |
| if (beamy == irqline) |
| Ram[0xFF09] |= Ram[0xFF0A]&0x02 ? 0x82 : 0x02; |
| } |
| |
| if (beamx&1) { // perform these only in every second cycle |
| if (t2on && !((timer2--)&0xFFFF)) {// Timer2 permitted |
| timer2=0xFFFF; |
| Ram[0xFF09] |= Ram[0xFF0A]&0x10 ? 0x90 : 0x10; // interrupt |
| } |
| if (t3on && !((timer3--)&0xFFFF)) {// Timer3 permitted |
| timer3=0xFFFF; |
| Ram[0xFF09] |= Ram[0xFF0A]&0x40 ? 0xC0 : 0x40; // interrupt |
| } |
| if (!CharacterWindow && !HBlanking && !VBlanking) { |
| // we are on the border area, so use the frame color |
| *((int*)(scrptr+4)) = framecol; |
| } |
| if (scrptr != endptr) |
| scrptr+=8; |
| } else { |
| if (t1on && !timer1--) { // Timer1 permitted decreased and zero |
| timer1=(t1start-1)&0xFFFF; |
| Ram[0xFF09] |= Ram[0xFF0A]&0x08 ? 0x88 : 0x08; // interrupt |
| } |
| |
| if (!(HBlanking |VBlanking)) { |
| if (SideBorderFlipFlop) { // drawing the visible part of the screen |
| // call the relevant rendering function |
| //switch (scrattr) { |
| // case 0: |
| // hi_text(); |
| // break; |
| // case REVERSE : |
| // rv_text(); |
| // break; |
| // case MULTICOLOR|REVERSE : |
| // mc_text_rvs(); |
| // break; |
| // case MULTICOLOR : |
| // mc_text(); |
| // break; |
| // case EXTCOLOR|REVERSE : |
| // case EXTCOLOR : |
| // ec_text(); |
| // break; |
| // case GRAPHMODE|REVERSE : |
| // case GRAPHMODE : |
| // hi_bitmap(); |
| // break; |
| // case EXTCOLOR|MULTICOLOR : |
| // case GRAPHMODE|EXTCOLOR : |
| // case GRAPHMODE|MULTICOLOR|EXTCOLOR : |
| // case REVERSE|MULTICOLOR|EXTCOLOR : |
| // case GRAPHMODE|MULTICOLOR|EXTCOLOR|REVERSE : |
| // mcec(); |
| // break; |
| // case GRAPHMODE|MULTICOLOR : |
| // case GRAPHMODE|MULTICOLOR|REVERSE : |
| // mc_bitmap(); |
| // break; |
| // default: |
| // illegalbank(); |
| // break; |
| //} |
| x = (x + 1) & 0x3F; |
| } |
| if (!CharacterWindow) { |
| // we are on the border area, so use the frame color |
| *((int*)scrptr) = framecol; |
| } |
| } |
| |
| CycleCounter++; |
| if (!(CycleCounter & 0x03) && buffer && int(count) > 0) { |
| static unsigned int remainder = 0; |
| unsigned int samples = (playbackSpeed + remainder) / 4; |
| if (samples) { |
| renderSound(samples, buffer); |
| if (sidCard) { |
| short imBuf[128]; |
| sidCard->calcSamples(imBuf, samples); |
| unsigned int i = samples - 1; |
| do { |
| buffer[i] += (short)(int(imBuf[i]) * int(masterVolume) / 10); |
| }while (i--); |
| } |
| storeToBuffer(buffer, samples); |
| } |
| remainder = (playbackSpeed + remainder) % 4; |
| count -= samples; |
| buffer += samples; |
| } |
| } |
| if (aligned_write) { |
| *aw_addr_ptr = aw_value; |
| aligned_write = false; |
| } |
| switch (ClockingState|(beamx&1)) { |
| case TRFSH|1: |
| case TSS|1: |
| case TDS|1: |
| case TDS: |
| cpuptr->process(); |
| break; |
| case THALT1|1: |
| case THALT2|1: |
| case THALT3|1: |
| cpuptr->stopcycle(); |
| ClockingState<<=1; |
| break; |
| } |
| |
| } while (int(count) > 0 && buffer); |
| |
| render_ok = false; |
| } |
| |
| void TED::enableChannel(unsigned int channel, bool enable) |
| { |
| channelMask[channel % 3] = enable ? -1 : 0; |
| if (sidCard) sidCard->enableDisableChannel(channel, enable); |
| } |
| |
| void TED::enableSidCard(bool enable, unsigned int disableMask) |
| { |
| if (enable) { |
| if (sidCard) |
| return; |
| sidCard = new SIDsound(SID8580, disableMask); |
| sidCard->setSampleRate(TED_SOUND_CLOCK); |
| } else { |
| if (!sidCard) |
| return; |
| delete sidCard; |
| sidCard = 0; |
| } |
| } |
| |
| TED::~TED() |
| { |
| if (filter) |
| delete filter; |
| } |
| //-------------------------------------------------------------- |
| |