(C64) SID AND CPU emulated in Javascript !

Topics pertaining to the emulation or simulation of the 65xx microprocessors and their peripheral chips.
Post Reply
mstram
Posts: 39
Joined: 26 Dec 2009

(C64) SID AND CPU emulated in Javascript !

Post by mstram »

Mihály Horváth (Hermit), has recently (last month) released his JsSID emulation :

It will play *most* SID's but not the "real special / tricky ones ".

He's doing some interesting things in the code, to make a "~1 M / cycle" SID work while using a fraction of that cycle count.

Listen to it here
http://hermit.sidrip.com/jsSID.html

Download it here :

http://csdb.dk/release/?id=145523

http://csdb.dk/release/?id=145493

SID emulation in Javascript !

Code: Select all

It's been a while since I released at CSDB. While I was creating my new
homepage I wanted to make it possible to play SIDs directly in the browser by
the visitors. As I haven't found any suitable thing for my needs in small size (
10..20kbyte), I decided to create a pure JavaScript SID player in the last 2
weeks. I only tested it in Firefox, but Chabee reported to work it in Chrome
and Safari. I count on your feedbacks... An extract from the README about what
it can do:


Features of jsSID that I think need to be mentioned:
-jsSID.js is very small in size (14kbyte), coded from scratch, so loading time on slow net-connections will still be adequate
-Audio-frequency (mostly 44.1kHz) operation, not 1MHz, so the CPU usage is very low despite being written in JS
-Clean sound, thin and high-pitched sounds are cleaned / band-limited algorithmically (e.g. Robocop3 title music intro)
-ADSR delay-bug/wraparound is simulated, so the soundstarts of modern tunes in SIDs are crisp as on the original SID
-6581 and 8580 model-changes are supported, they have different cutoff/resonance curves and combined waveforms
-Combined waveforms are generated algorithmically, not read from low-resolution tables (first of its kind, based on SID schematic)
-Background noise can be added to give a bit more analog feel (though it's just simple whiteniose yet, not VIC noise)
-CPU emulation is cycle-based despite 44.1kHz operation (called more times appropriately during one sample-period)
-Vsync- and CIA-timed single- and multispeed tunes are supported (though there are exceptions like digi tunes)
-Illegal opcodes are supported by the CPU emulation to a degree (most LAX and SAX instructions, needed e.g. by 1raster-tracker)
-Interfacing through easy-to-use function calls (load/start/stop/etc.), playing a SID is as simple as playSID('URL',subtune);
-Callbacks can be set for various events, e.g. when a SID with given length ends (this eases auto-advance playback)

Not supported:
-Digi playback is totally left off from jsSID, it's targeted for authentic clean SID sound instead
-jsSID is not a real C64/SID environment, CIA and raster-interrupts are not emulated exactly, so some SIDs won't play:
Digis won't play at all. Some older players with complex/unusual CIA-IRQ timing may have issues (e.g. Richard Joseph / Galway tunes.)
Last edited by mstram on Mon Mar 07, 2016 1:38 pm, edited 1 time in total.
mstram
Posts: 39
Joined: 26 Dec 2009

Re: (C64) SID AND CPU emulated in Javascript !

Post by mstram »

Some interesting comments in the source code :

Code: Select all

//And now, the combined waveforms. The resid source simply uses 4kbyte 8bit
 // samples from wavetable arrays, says these waveforms are mystic due to the
 // analog behaviour.

 //It's true, the analog things inside SID play a significant role in how the
 // combined waveforms look like, but process variations are not so huge that
// cause much differences in SIDs.

 // After checking these waveforms by eyes, it turned out for me that these
 // waveform are fractal-like, recursively approachable waveforms.

 //My 1st thought and trial was to store only a portion of the waveforms in
 // table, and magnify them depending on phase-accumulator's state.

 //But I wanted to understand how these waveforms are produced. I felt from the
 // waveform-diagrams that the bits of the waveforms affect each other,
 //hence the recursive look. A short C code proved by assumption, I could
 // generate something like a pulse+saw combined waveform.

 //Recursive calculations were not feasible for MCU of SwinSID, but for jsSID I
 //could utilize what I found out and code below generates the combined waveforms
 // into wavetables.

 // To approach the combined waveforms as much as possible, I checked out the
 // SID schematic that can be found at some reverse-engineering sites...

 //The SID's R-2R ladder WAVE DAC is driven by operation-amplifier like
 // complementary FET output drivers, so that's not the place where I first
 // thought the magic happens.

 // These 'opamps' (for all 12 wave-bits) have single FETs as inputs, and they
 // switch on above a certain level of input-voltage, causing 0 or 1 bit as R-2R
 // DAC input.

 // So the first keyword for the workings is THRESHOLD. These FET inputs are
 // driven through serial switch FETs (wave-selector) that normally enables one
 //waveform at a time.

 // The phase-accumulator's output is brought to 3 kinds of circuitries for the
 // 3 basic waveforms. The pulse simply drives
 // all wave-selector inputs with a 0/1 depending on pulsewidth, the sawtooth
 // has a XOR for triangle/ringmod generation, but what
 // is common for all waveforms, they have an open-drain driver before the wave-
 // selector, which has FETs towards GND and 'FET resistor' towards the power-
 // supply rail.

 // These outputs are clearly not designed to drive high loads, and normally
 // they only have to drive the FETs input mentioned above.

 // But when more of these output drivers are switched together by the switch-
 // FETs in the wave-selector, they affect each other by loading each other.

 // The pulse waveform, when selected, connects all of them together through a
 // fairly strong connection, and its signal also affects the analog level (pulls
 // below the treshold)...

 // The farther a specific DAC bit driver is from the other, the less it affects
 // its output. It turned out it's not powers of 2 but something else,
 //that creates similar combined waveforms to that of real SID's...

 // The analog levels that get generated by the various bit drivers, that pull
 // each other up/down depends on the resistances the components inside the SID
 // have.

 // And finally, what is output on the DAC depends on whether these analog
 // levels are below or above the FET gate's threshold-level,

 // That's how the combined waveform is generated. Maybe I couldn't explain
// well enough, but the code below is simple enough to understand the mechanism
// algoritmically.

 //This simplified schematic example might make it easier to understand
 //sawtooth+pulse combination (must be observed with monospace fonts):

 //                               _____            |-    .--------------.   /\/\--.
 // Vsupply                /  .----| |---------*---|-    /    Vsupply   !    R    !      As can be seen on this schematic,
 //  ------.       other   !  !   _____        !  TRES   \       \      !         /      the pulse wave-selector FETs
 //        !       saw bit *--!----| |---------'  HOLD   /       !     |-     2R  \      connect the neighbouring sawtooth
 //        /       output  !  !                          !      |------|-         /      outputs with a fairly strong
 //     Rd \              |-  !WAVEFORM-SELECTOR         *--*---|-      !    R    !      connection to each other through
 //        /              |-  !SWITCHING FETs            !  !    !      *---/\/\--*      their own wave-selector FETs.
 //        ! saw-bit          !    _____                |-  !   ---     !         !      So the adjacent sawtooth outputs
 //        *------------------!-----| |-----------*-----|-  !          |-         /      pull each other upper/lower
 //        ! (weak drive,so   !  saw switch       !THRES-!  `----------|-     2R  \      depending on their low/high state and
 //       |- can be shifted   !                   ! HOLD !              !         /      distance from each other, causing
 //  -----|- by neighbours    !    _____          !      !              !     R   !      the resulting analog level that
 //        ! up or down)      *-----| |-----------'     ---            ---   /\/\-*      will either turn the output on or not.
 //   GND ---                 !  pulse switch                                     !      (Depending on their relation to treshold.)
 //
 //(As triangle waveform connects adjacent bits by default, the above explained effect becomes even stronger, that's why combined waveforms with thriangle are at 0 level most of the time.)


 function combinedWF(channel,wfarray,index,differ6581) { //on 6581 most combined waveforms are essentially halved 8580-like waves
  if(differ6581 && SID_model==6581.0)
	  index&=0x7FF;
		combiwf = (wfarray[index]+prevwavdata[channel])/2;
		prevwavdata[channel]=wfarray[index];
		return combiwf;
 }

 function createCombinedWF(wfarray,bitmul,bitstrength,treshold) { //I found out how the combined waveform works (neighboring bits affect each other recursively)
  for (var i=0; i<4096; i++) {
		   wfarray[i]=0; //neighbour-bit strength and DAC MOSFET treshold is approximately set by ears'n'trials

			  for (var j=0; j<12;j++) {
			 	    var bitlevel=0;

           for (var k=0; k<12; k++) {
				  	    bitlevel += ( bitmul/Math.pow(bitstrength,Math.abs(k-j)) ) * (((i>>k)&1)-0.5) ;
				  		}

           wfarray[i] += (bitlevel>=treshold)? Math.pow(2,j) : 0;
		   }
    wfarray[i]*=12;  }
 }
Last edited by mstram on Mon Mar 07, 2016 1:39 pm, edited 1 time in total.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: (C64) SID AND CPU emulated in Javascript !

Post by BigEd »

It's funny to me, but of course perfectly reasonable, that there's a lot of people interested principally in the music side of the C64, and will emulate the CPU only as a necessary prerequisite to running the programs which drive the sound chip. I see that BCD isn't required for this purpose!
mstram
Posts: 39
Joined: 26 Dec 2009

Re: (C64) SID AND CPU emulated in Javascript !

Post by mstram »

If you mean an emulated CPU driving a real SID, I don't know if many people are doing that, but I guess it's possible (FPGA ?)

The above project is all software, no hw involved :)

It's amazing with our blazing CPU's that (formerly considered) "slow" Javascript and Web Browsers can do this kind of thing.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: (C64) SID AND CPU emulated in Javascript !

Post by BigEd »

Indeed, JS engines are really impressive these days (and of course are running on fast CPUs themselves.)

I didn't mean a mix of hardware and software, just that to drive a SID you need to run a 6502 program, so this emulator, like all SID players I suppose, has to emulate the 6502. Including a handful of undocumented instructions, because some of the players use them.
mstram
Posts: 39
Joined: 26 Dec 2009

Re: (C64) SID AND CPU emulated in Javascript !

Post by mstram »

BigEd wrote:
Indeed, JS engines are really impressive these days (and of course are running on fast CPUs themselves.)

I didn't mean a mix of hardware and software, just that to drive a SID you need to run a 6502 program, so this emulator, like all SID players I suppose, has to emulate the 6502. Including a handful of undocumented instructions, because some of the players use them.
Well to play a xxx.sid file you need to emulate or have a real 6502, since the sid file is 6502 code.

But why do you need a 6502 program to drive the SID chip ? (or emulated SID ?)

And as for your comment about no BCD :

From the source file

Code: Select all

function CPU () //the CPU emulation for SID/PRG playback (ToDo: CIA/VIC-IRQ/NMI/RESET vectors, BCD-mode)
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: (C64) SID AND CPU emulated in Javascript !

Post by BigEd »

It's an interesting emulation problem, especially if the emulator also needs to know a little more about the C64, say to get CIA IRQs exact. I've found another JS SID player/emulator:
https://github.com/wothke/websid/blob/m ... idengine.c
http://www.wothke.ch/websid/ (beware autoplaying audio)

I see I've inadvertently implied that only a 6502 can drive a SID - I don't mean to do that. As an 8-bit peripheral chip, a SID can serve in any system I'm sure. What I meant is that the body of musical work out there is in the form of a tune coupled with a player, and the player is almost always going to be 6502 code for a C64, or something like one.
Post Reply