Thursday 30 June 2016

Part 15: Finishing cassette integration

Foreword

In the previous blog we started to implement tape emulation for our emulator. In this blog we will continue.

Implementing the timer

Let us start with implementing the timer.

I think probably a good place to start, is just to get an overview of how timers work in the CIA chip

Overview

We scratched the surface on timers in a previous blog post where implemented the flashing cursor.

It might not have been that obvious from that blog post, but the CIA actually have 2 timers: Timer A and Timer B.

Each of these timers have it own set of registers which are almost identical.

To avoid a cluttered discussion, I will exclusively focus on the registers of Timer A. Please note, however, that you can apply exactly the same reasoning to timer B.

Also, in this section, when I am talking about The Timer, I am implying Timer A.

Let us start with summarising what we already know about timers on the CIA:
  • Timers are actually 16-bit count down counters. When a counter reaches 0, an underflow condition occurs and an interrupt triggers.
  • These counters can be driven by a number of clock sources. The most notable clock source is 02 which clocks at 1Mhz
At any point in time you can read the contents of the timer counter, by reading register locations 4 & 5. Location 4 and 5 is the Low/High byte of the counter of timer A.

It is interesting to note that when you write a value to register 4 or 5, the timer will not immediately update the counter with given value. Instead, all writes to registers are stored in a special register, called a latch.

So, how do you set the counter to count down from a specific number? There are two ways.

The first way is the brute force way. Writing a 1 to bit 4 of register 14 will force the timer to load the counter with the value stored in the latch.

The second way is when the counter reaches zero, the timer will automatically reload the counter with the value stored in the latch.

Next, question: How do you start the timer? You write a 1 to bit 0 of register 14. Conversely, if you write a 0 to bit zero, the timer will halt counting down. If you resume the count down process by writing a one again to bit 0, the counter will just continue down from the value it previously stopped at.

Lets conclude this section by discussing the two modes in which CIA timers can operate: One-Shot and Continuous.

Both One-Shot and Continuous mode will count down till underflow, raise an interrupt and reload the counter with the value stored in the latch. The subtle difference between the two modes will actually happen after executing previous mentioned two actions.

In One-Shot mode countdown will halt after an underflow condition. This halting process will also set the start/stop bit (e.g. bit 0 of location 14) to zero.

In Continuous mode, the counter will automatically continue to countdown after the counter was reloaded during an underflow. Continuous mode is a kind of an unattended mode.

Coding


We will start off with a new file called Timer.js. I will again start showing the majority of the code, and then explaining it:

function timer(alarmManager) {
  var myAlarmManager = alarmManager;
  var isEnabled = false;
  var ticksBeforeExpiry = 0;
  myAlarmManager.addAlarm(this);
  var timerHigh = 255;
  var timerLow = 255;
  var continious = false;
 
  this.getIsEnabled = function() {
    return isEnabled;
  }

  this.getTicksBeforeExpiry = function() {
    return ticksBeforeExpiry;
  }

  this.setTicksBeforeExpiry = function(ticks) {
    ticksBeforeExpiry = ticks;
  }

  this.trigger = function() {
    //cuase interrupt
    ticksBeforeExpiry = (timerHigh << 8) | timerLow;
    if (!continious)
      isEnabled = false;
  }

  this.setTimerHigh = function(high) {
    timerHigh = high;
  }

  this.setTimerLow = function(low) {
    timerHigh = low;
  }

  this.getTimerHigh = function() {
    return (ticksBeforeExpiry >> 8);
  }

  this.getTimerLow = function() {
    return (ticksBeforeExpiry & 0xff);
  }

  this.setControlRegister = function (byteValue) {
    if ((byteValue & (1 << 4)) != 0)
      ticksBeforeExpiry = (timerHigh << 8) | timerLow;

    continious = ((byteValue & (1 << 3)) == 0) ? true : false;

    isEnabled = ((byteValue & 1) == 1) ? true : false;
  
  }

  this.getControlRegister = function() {
    var tempValue = 0;
    if (continious)
      tempValue = tempValue | 1 << 3;
    if (isEnabled)
      tempValue = tempValue | 1;
    return tempValue;
  }

}

Needless to say, this class will also add itself to the alarm manager, so I have implemented all the methods required by AlarmManager, which is the following:
  • getIsEnabled
  • getTicksBeforeExpiry
  • setTicksBeforeExpiry
  • trigger
Please note that at this point we are still not sure about how the interrupt functionality is going to work, so again in the trigger method, I have just added a comment to remind us to implement  a trigger-interrupt.

Now, lets look at the functionality which is unique to the timer itself. The first is the two private variables timerHigh and timerLow. As you can see only a setter is provided for access to these private variables variables and no getter. This nicely models the fact that the timer latches are write only registers. You can also see that assign a default value of 255 to each of these private variables. This is also the default when a real CIA powers up.

There is indeed a getTimerHigh and getTimerLow method, but as previously mentioned, it not does not return the contents of the timerHigh/timerLow private variables. It is using the timerTicksBeforeExpiry private variable.

Another timer related private variable is continuous. It is mainly utilised within the trigger method. Within  the method the Alarm is disabled when continuous is false.

Finally, let us look at the methods setControlRegister and getControlRegister. In effect, these two methods deals with the contents of location 14 of the CIA chip.

Implementing Interrupts

In this section we are going to discuss and implement CIA interrupt functionality into our emulator. Hopefully after this section we will have more clarity in what we need to implement for our timer and tape class during the event of an interrupt.

Overview

Up to this point in time we know that the CIA can generate interrupts for a number of different events.

The beauty of the CIA chip is that it collate all these interrupt into a single interrupt going to the CPU.

There are a couple of scenarios where you would like to block some of these interrupts (e.g. to mask an interrupt) so that it doesn't cause an interrupt on the CPU. You can exercise this option by writing to location 13.

When you write to location 13 for masking an interrupt or two, it is important that the Most significant bit of the byte you write is set to zero. This will inform the CIA to mask every interrupt which applicable bit is set to a one. For example, if you write 03h to location 13, both the timer A and timer B interrupts will be disabled.

If the byte you write to location 13 has the MSB set to a one, the opposite will happen. Each bit set to a one will enable the applicable interrupt.For example, writing 83h to location 13 will enable the Timer A and Timer B interrupts.

When you read from location you will see which interrupts you have masked, but which interrupts actually have occurred. This will enable you to figure out which interrupt actually interrupted the CPU.

It is important to note that reading location 13 has one side effect. Reading this location will reset all occurred interrupts to zero. So it is important that which ever piece of code read this location, should store it somewhere so that all applicable events can be served, if necessary.

Coding

Lets code the interrupt functionality.

We will wrap all this functionality in a file InterruptController.js Our first take on the class will look as follows:

function interruptController() {
  var mycpu;
  var interruptMask = 0;
  var interruptsOccured = 0;

  this.setCpu = function(cpu) {
    mycpu = cpu;
  } 

  this.setInterruptMask = function(mask) {
    if (mask > 127) {
      interruptMask = interruptMask | mask;
    } else {
      interruptMask = interruptMask & (~mask & 0xff);
    }

  }

  this.getInterrupts = function() {
    var temp = interruptsOccured;
    interruptsOccured = 0;
    return temp;
  }

}

Here we closely model our theoretical discussion. Writing to the class we first check if bit 7 is, then we OR the input to the private variable interruptMask. If bit 7 is a zero, we mask off relevant bits.

Nothing interesting happening in the read. We return the interrupts that have occurred and reset the private variable storing this information.

Next, let us service some public methods simulating inerrupts for Time A, Timer B and FLAG:

  this.interruptFlag1 = function() {
    interruptsOccured = interruptsOccured | 16 | 128;
    if ((interruptMask & 16) == 0) 
      return;
    mycpu.setInterrupt();
  }

  this.interruptTimerA = function() {
    interruptsOccured = interruptsOccured | 1 | 128;
    if ((interruptMask & 1) == 0) 
      return;
    mycpu.setInterrupt();
  }

  this.interruptTimerB = function() {
    interruptsOccured = interruptsOccured | 2 | 128;
    if ((interruptMask & 2) == 0) 
      return;
    mycpu.setInterrupt();
  }


So, basically or Timer classes and Tape class should call one of these methods in the event of an interrupt. Each method then first checks whether applicable interrupt is enable and then call setInterrupt on the CPU class if it is enabled.

Glueing everything together

Time to glue everything together.

First, lets finish off the interrupt functionality within the Tape and Timer classes.

We start with Tape.js:

function tape(alarmManager, interruptManager) {
  var myAlarmManager = alarmManager;
  var myInterruptManager = interruptManager;
  var tapeData;
  var posInTape;
  var isEnabled = false;
  var ticksBeforeExpiry = 0;
  myAlarmManager.addAlarm(this);

  this.attachTape = function(file) {
       var reader = new FileReader();
       reader.onload = function(e) {
         var arrayBuffer = reader.result;
         tapeData = new Uint8Array(arrayBuffer);
         posInTape = 0x14;
         scheduleNextTrigger();
         alert("Tape attached");
       }
       reader.readAsArrayBuffer(file);

  }

  this.setMotorOn = function(bit) {
    isEnabled = (bit == 0) ? true : false;
  }

  function scheduleNextTrigger() {
    ticksBeforeExpiry = tapeData[posInTape] << 3;
    posInTape++;
  }

  this.getIsEnabled = function() {
    return isEnabled;
  }

  this.getTicksBeforeExpiry = function() {
    return ticksBeforeExpiry;
  }

  this.setTicksBeforeExpiry = function(ticks) {
    ticksBeforeExpiry = ticks;
  }

  this.trigger = function() {
    myInterruptManager.interruptFlag1();
    scheduleNextTrigger();
  }

}


That was relatively painless.

Next up, the timers. Here we are faced with a bit of a problem. It make sense to create one separate timer instance for timer A and another instance for timer B. Currently, however there is know way for a timer instance to know whether it is timer A or B. This knowledge is necessary so that the timer instance can call the correct method on the InteruuptController class during an interrupt.

We sort of need to inject this into the timer when we create a timer instance. This will enable the following changes within our Timer Class:

function timer(alarmManager, InterruptController, timerName) {

  ...  

  var myname = timerName;
  var myInterruptController = InterruptController; 
  ...

  this.trigger = function() {
    if (myname == "A") {
      myInterruptController.interruptTimerA();
    } else {
      myInterruptController.interruptTimerB();
    }    ticksBeforeExpiry = (timerHigh << 8) | timerLow;
    if (!continious)
      isEnabled = false;
  }

...

}




From this code we see that when creating a timer instance, either an A or a B should be passed as timerName.

Time to wire everything into the memory class:

function memory(allDownloadedCallback, keyboard, timerA, timerB, interruptController,tape)

{
...
  var mytimerA = timerA;
  var mytimerB = timerB;
  var myinterruptController = interruptController;
  var mytape = tape;...


  function ciaRead(address) {
    if (address == 0xdc01) {
      return keyboardInstance.getColumnByte(mainMem[0xdc00]);
    } else if (address == 0xdc04) {
      return mytimerA.getTimerLow();
    } else if (address == 0xdc05) {
      return mytimerA.getTimerHigh();
    } else if (address == 0xdc06) {
      return mytimerB.getTimerLow();
    } else if (address == 0xdc07) {
      return mytimerB.getTimerHigh();
    } else if (address == 0xdc0d) {
      return myinterruptController.getInterrupts();
    } else if (address == 0xdc0e) {
      return mytimerA.getControlRegister();
    } else if (address == 0xdc0f) {
      return mytimerB.getControlRegister();
    } else {
      return mainMem[address];
    }

  }

  function ciaWrite(address, byteValue) {
    if (address == 0xdc04) {
      return mytimerA.setTimerLow(byteValue);
    } else if (address == 0xdc05) {
      return mytimerA.setTimerHigh(byteValue);
    } else if (address == 0xdc06) {
      return mytimerB.setTimerLow(byteValue);
    } else if (address == 0xdc07) {
      return mytimerB.setTimerHigh(byteValue);
    } else if (address == 0xdc0d) {
      return myinterruptController.setInterruptMask(byteValue);
    } else if (address == 0xdc0e) {
      return mytimerA.setControlRegister(byteValue);
    } else if (address == 0xdc0f) {
      return mytimerB.setControlRegister(byteValue);
    } else {
      mainMem[address] = byteValue;
    }
    
  }
  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if ((address >= 0xdc00) & (address <= 0xdcff)) {
      return ciaRead(address);
    }     return mainMem[address];
  }

  this.writeMem = function (address, byteval) {
    if ((address >= 0xdc00) & (address <= 0xdcff)) {
      ciaWrite(address, byteval);
      return;
    } else if (address == 1) {
      var temp = byteval & 32;
      temp = temp >> 5;
      tape.setMotorOn(temp);
    }      
    mainMem[address] = byteval;
  }

}



All CIA location accesses has moved into two separate methods.

One thing also worth mentioning is the check if we write to memory location 1. In such a scenario we isolate the motor bit and do the appropriate action on the tape class.

We need to do some wiring in our index page as well. So we start with the initialisation code:

    <script language="JavaScript">

      var mykeyboard = new keyboard();

      var myAlarmManager = new alarmManager();
      var myInterruptController = new interruptController();
      var myTimerA = new timer(myAlarmManager, myInterruptController,"A");
      var myTimerB = new timer(myAlarmManager, myInterruptController, "B");
      var myTape = new tape(myAlarmManager, myInterruptController);      
      var mymem = new memory(postInit,mykeyboard,myTimerA, myTimerB, myInterruptController, myTape);
      var mycpu = new cpu(mymem);
      myAlarmManager.setCpu(mycpu);
      myInterruptController.setCpu(mycpu);      
      var myvideo = new video(document.getElementById("screen"), mymem);
      var running = false;
      var breakpoint = 0;
...

We also have some unfinished business in the runBatch method:

      function runBatch() {
        if (!running)
          return;
        myvideo.updateCanvas();
        var targetCycleCount =  mycpu.getCycleCount() + 20000;
        while (mycpu.getCycleCount() < targetCycleCount) { 
          mycpu.step();
          myAlarmManager.processAlarms();
          //if (mycpu.getCycleCount() > 6000000)            
          //  mymem.setSimulateKeypress();
          var blankingPeriodLow = targetCycleCount - 100;
          if ((mycpu.getCycleCount() >= blankingPeriodLow) & (mycpu.getCycleCount() <= targetCycleCount)) {
            mymem.writeMem(0xD012, 0);
          } else  {
            mymem.writeMem(0xD012, 1);
          }
          if (mycpu.getPc() == breakpoint) {
            stopEm();
            return;
          }
        }
        //mycpu.setInterrupt();
      }
      

I removed the call to setInterrupt and added a call to processAlarms of the alarmmanager.

We still need something to simulate pressing play on tape with the effect of bringing the sense line low.

We will delegate this responsibility to the Memory class:

function memory(allDownloadedCallback, keyboard, timerA, timerB, interruptController,tape)

{
 var playPressed = false;

 ...


  this.togglePlayPresed = function() {
    playPressed = !playPressed;
  }
 ...

  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if ((address >= 0xdc00) & (address <= 0xdcff)) {
      return ciaRead(address);
    } else if (address == 1) {
      var temp = mainMem[address] & 239;
      if (!playPressed)
        temp = temp | 16;
      return temp;
    }
    return mainMem[address];
  }

}

We have exposed a method togglePlaypressed that you can call outside the memory class which will toggle the state of the sense line.

On our index page we can just add a button which will call this method on click:

...
<br/>
<input type="file" id="files" name="myfile"/>
<button onclick="attachTape()">Attach</button>
</br>
<button onclick="mymem.togglePlayPresed()">Play</button>
</br>
<textarea id="registers" name="reg" rows="1" cols="60"></textarea>
<br/>
...


Some Final touches

Some testing yielded that it is not so a good idea to set an interrupt flag in the CPU class when an interrupt occurs.You end off with times that there is still a pending interrpt in the CPU class, but the interrupt might already have been cleared by reading the flags register in the interrupt class,

A better approach would therefore be to rather let the CPU class ask the Interrupt class whether an Interrupt has occured

  this.step = function () {
    if ((myInterruptController.getCpuInterruptOcurred()) & (interruptflag == 0)) {
        interruptOcurred = 0;
        Push(pc >> 8);
        Push(pc & 0xff);
        breakflag = 0;
        Push(getStatusFlagsAsByte());
        breakflag = 1;
        interruptflag = 1;
        tempVal = localMem.readMem(0xffff) * 256;
        tempVal = tempVal + localMem.readMem(0xfffe);
        pc = tempVal;
    }

This will yield an interrupt class as follows:

function interruptController() {
  var mycpu;
  var interruptMask = 0;
  var interruptsOccured = 0;
  var interruptCpu = false;

  this.setCpu = function(cpu) {
    mycpu = cpu;
  } 

  this.setInterruptMask = function(mask) {
    if (mask > 127) {
      interruptMask = interruptMask | mask;
    } else {
      interruptMask = interruptMask & (~mask & 0xff);
    }

  }

 this.getCpuInterruptOcurred = function() {
    return interruptCpu;
  }
  this.getInterrupts = function() {
    var temp = interruptsOccured;
    interruptsOccured = 0;
    interruptCpu = false;
    return temp;
  }

  this.interruptFlag1 = function() {
    interruptsOccured = interruptsOccured | 16 | 128;
    if ((interruptMask & 16) == 0) 
      return;
    interruptCpu = true;
    //mycpu.setInterrupt();
  }

  this.interruptTimerA = function() {
    interruptsOccured = interruptsOccured | 1 | 128;
    if ((interruptMask & 1) == 0) 
      return;
    interruptCpu = true;
    //mycpu.setInterrupt();
  }

  this.interruptTimerB = function() {
    interruptsOccured = interruptsOccured | 2 | 128;
    if ((interruptMask & 2) == 0) 
      return;
    interruptCpu = true;
    //mycpu.setInterrupt();
  }

}

With all this we managed to get our emulator to find the header on the tape:


This concludes this blog.

In Summary


In this blog we managed to emulate tape emulation up to the point where our emulator could identify the header on tape.

In the next blog we will continue with our mission to emulate the game Dan Dare.

Dan Dare is also a game where its loader shows flashing colourful borders. So it would make sense as a next to try and emulate these borders.

This goal will force us to jack up the capabilities of our Video class.

Till next time!

Thursday 23 June 2016

Part 14: Tape emulation

Foreword

In the previous blog we managed to integrate our emulator with a physical keyboard.

In this blog we will start to implement functionality to emulate tape input. Well, not from a physical C64 tape, but from a tape image file, which is pretty close to the raw format of a physical C64 tape.

We will start off again with some theory, covering both a bit of the technical details on the tape functionality in the C64 and we will be deciphering the .tap file format. A .tap file is essentially a tape image file.

After the theory we will attempt to start and implement the tape emulation functionality in our emulator. In this exercise we will actually discover some redesign surprises. We will therefore see how far we can get to implement the tape functionality in this blog and continue in the next blog.

Some insight into future posts

Up to this point in time our emulator has enough functionality allowing you to enter a Basic program and running it.

I think it is about time we move our goals to something else. My next goal in mind is to actually see if we can emulate a game.

The target game I have in mind for future posts is Dan Dare - Pilot of the future. This game is available from many websites as a .tap file. Hence, this is the reason why we will be exploring tape emulation in this blog.

In coming posts I will also be following an incremental approach. Here is some sub targets:

  • See if we can emulate the tape loading process up to the point where our emulator shows the message FOUND DAN DARE. If we get this far, we know that our tape emulation is more or less on track.
  • Emulate the loading process. When the DAN DARE game loads, it shows flashing borders and a splash screen. So we will incrementally add functionality to cater for this.
  • Show the game intro screen.
This is more or less the steps we will follow to emulate the game.

C64 Tape Technicalities

Let us begin by finding out how the Commodore Datasette is wired to the C64. Here is a small snippet of the schematic what highlights this for us:


The pins of the Tape connector is shown on the right. Let us briefly pause and discuss the purpose of the pins. There are four pins of importance:

  • Read
  • Write
  • Motor
  • Cassette sense
The read and write pins speak for themselves.

The Motor pin remind us of the remote jack early tape recorders was equipped with, allowing the use of microphones that enables you to stop/resume recording via a switch on the microphone itself.

The sense pin actually informs the C64 when the play, rewind or fastforward is depressed. This aid in only enabling the spindle motor when necessary.

It is important to take note of the functions of the sense and motor pins since they would also effect emulation.

Now, how is the tape drive interfaced to the C64?

Firstly, the motor, sense and write pins are connected directly to the CPU. Remember that the 6510 is a special addition of the 6502 which contains 8 additional pins which you could either read or set bits from. The 6510 dedicates memory locations 0 and 1 for the purpose of these pins.

The Read pin is connected to the FLAG pin of CIA chip number 1. The flag pin triggers an interrupt when the data on the pin transitions from a one to a zero. A transition from a zero to a one doesn't trigger any interrupt at all.

Needless to say, the read pin gets its data from the tape. Simple, but one might wonder: The read pin provide discrete 0's and 1's, whereas the tape is an analogue device that can provide you with any voltage in between. So really, when does the tape unit send a one and when does it send a zero down the read wire? The tape unit makes use of an encoding scheme called zero-crossing. The following image from wikipedia illustrate zero-crossing:

Ok, not shown in this picture is that the blue line represents 0 volts, everything above the line represents a positive voltage and everything below the blue line is a negative voltage. All in all when the voltage from the tape drops below 0 volt and become negative, a zero will be outputted on the read pin. Similarly, when the voltage approach zero volt and become positive, a one will be outputted to the read wire.

As stated earlier, only a transition from a one to a zero will cause an interrupt in the CIA. This is indicated by the 0's on the blue line in the diagram.

Information is extracted from this scheme by measuring the time that lapsed between two transitions. Different time periods have different meanings. As a matter of fact, all that the tape image file formats are storing is a sequence of durations. In the next section we are going discuss the .TAP file format.

The .TAP format

The following web site will give you detailed information on the .TAP format:

http://unusedino.de/ec64/technical/formats/tap.html

The highlights of the format is as follows:

  • Duration data starts at hex offset 14.
  • Each duration is represented by one byte. If you take this value and multiply it by 8, you will get the duration in number of CPU clock cycles.
Let us quickly work through an example. I am going to open a .tap file of Dan Dare in a hex editor:


I have highlighted the beginning of data at location 14h. As you might realise, the first couple of thousands of durations are all the same. If you ever listened to C64 tape, this observation makes perfect sense. Each file is preceded by mono tone of about 10 seconds. Lets see if we can verify this.

The repeating byte stops more or less at 6a13h. Converted to decimal, this equals 27155 durations. How long is a duration? The repeating byte is 30h and this we need to multiply with 8. The answer in decimal is 384 clock cycles.

Now 27155 x 384 = 10427520 clock cycles. We know our CPU is clocking at 1MHz, so the duration of the mono tone is 10.4 seconds.

Emulating a tape in our Emulator

We can summarise the tape emulation process in one sentence: Causing interrupts at predefined time intervals.

Lets take a working example using the Dan Dare .tap file again. For this example we will use the sequence of bytes after the monotone:

Lets convert the sequence of bytes to clock cycles:

56h = 86 * 8 = 688
42h = 66 * 8 = 528
42h = 66 * 8 = 528
30h = 48 * 8 = 384
30h = 48 * 8 = 384
42h = 66 * 8 = 528
30h = 48 * 8 = 384

So, the emulation process will be something like the following:
  • Wait 688 clock cycles
  • Cause an interrupt
  • Wait 528 clock cycles
  • Cause an interrupt
  • Wait another 528 clock cycles
  • Cause an interrupt
  • Wait 384 clock cycles
  • Cause an interrupt
And so on...

Coding the solution

Let us now try to write the above mentioned algorithm in JavaScript.

First, we need to give our emulator access to the binary contents of the .TAP file. The first instinct would be to use a XMLRequestObject for this purpose. But, as we know from previous posts, XMLRequestObject can only use files served by a webserver.

This means if we host our emulator on a web site for people to play on, they would limited to only .tap files that we provide.

Wouldn't it be nice, if we would allow a user to select a .tap file located on their local drive to emulate?

Indeed there is way to do that. HTML provides an input type called file. JavaScript can extract the file name from this element and load the contents of the file into an arraybuffer, even if it is local.

Wonderful! There might be a couple of questions onto why I didn't use these elements to load the C64 ROMS into the our emulator. This would have avoided the installation of a local webserver to test the emulator locally. The answer to this is that there is bit of a snag when using the input type file: You need to select the files manually. This would mean each time you open the emulator in a browser, you would need to manually select all three ROMS, and then boot the system. A bit of a tedious process!

So, let us add a file input element to our index page:
  <body onkeydown="mykeyboard.onkeydown(event)" onkeyup="mykeyboard.onkeyup(event)">
    <h1>6502 Emulator From Scratch</h1>
    <p>This is JavaScript Test</p>
<canvas id="screen" width="320" height="200">

</canvas>
<br/>
<input type="file" id="file" name="myfile"/>
<button onclick="">Attach</button>
</br>
<textarea id="registers" name="reg" rows="1" cols="60"></textarea>
<br/>
<textarea id="memory" name="mem" rows="15" cols="60"></textarea>

I have also added a button, so we can inform the emulator to load the tap file in an array buffer. The onclick event handler for this button this still needs to be defined. We will come back to this in moment.

I would like to encapsulate all the Tape functionality in a class of its own, so lets create the file Tape.js:

function tape() {
}

The first functionality I would like to implement in this class is to load the contents of a .tap file into an arraybuffer. Here is the code:

 var tapeData;

 this.attachTape = function(file) {
       var reader = new FileReader();
       reader.onload = function(e) {
         var arrayBuffer = reader.result;
         tapeData = new Uint8Array(arrayBuffer);
         alert("Tape attached");
       }
       reader.readAsArrayBuffer(file);
  }

Firstly we declare a private variable tapeData to store the contents of the .tap file.

The public method attachTape is the actual method our onclick event should call when we click the attach button. It accepts a Input file element as the parameter. The instance of FileReader is the class that does all the work for us. All in all the functionality to populate the arraybuffer is very similar to what we are doing when loading the C64 ROMS at bootup via XMLHTTPRequest objects.

As an added measure I am just showing an alert box to tell user if the attach process was successful.

Before we continue, we should just populate the onclick event of the Attach button:

  <body onkeydown="mykeyboard.onkeydown(event)" onkeyup="mykeyboard.onkeyup(event)">
    <h1>6502 Emulator From Scratch</h1>
    <p>This is JavaScript Test</p>
<canvas id="screen" width="320" height="200">

</canvas>
<br/>
<input type="file" id="file" name="myfile"/>
<button onclick="myTape.attachTape(document.getElementById('file').files[0])">Attach</button>
</br>
<textarea id="registers" name="reg" rows="1" cols="60"></textarea>
<br/>
<textarea id="memory" name="mem" rows="15" cols="60"></textarea>


So, what do we code next? Well, as we have seen earlier, the core of tape emulation is to wait a certain amount of clock cycles before triggering an interrupt. We are doing something very similar in the runBatch method for our timer interrupt. We could probably do a similar hack in the runBatch method for the tape functionality, but this starting to look a bit clunky.

It would actually be nice to create a class that will manage the need for triggering events at certain clock cycles for us. With this in mind I have created the following class within new file called AlarmManager.js:

function alarmManager() {
  var myCpu;
  var alarms = [];
  var lastCycleCount = 0;

  this.setCpu = function (cpu) {
    myCpu = cpu;
  }

  this.addAlarm = function (alarmObject) {
    alarms.push(alarmObject);
  }

  this.processAlarms = function () {
    var i;
    var numTicks = myCpu.getCycleCount() - lastCycleCount;
    lastCycleCount = myCpu.getCycleCount();
    for (i = 0; i < alarms.length; i++) {
      var currentAlarm = alarms[i];
      if (currentAlarm.getIsEnabled()) {
        var ticksBeforeExpiry = currentAlarm.getTicksBeforeExpiry() - numTicks;
        if (ticksBeforeExpiry > 0) {
          currentAlarm.setTicksBeforeExpiry(ticksBeforeExpiry);
        } else {
          currentAlarm.setTicksBeforeExpiry(0);
          currentAlarm.trigger();
        }
      }
    }
  }
}

Lets discus this class.

Firstly, if a particular class, like tape, have the need to trigger an event at a certain clock cycle, it needs to call addAlarm to add itself to the alarms array.

The next method of interest is the procesAlarms. You need to invoke this method within the runBatch method each time you have executed a cpu instruction.

The processAlarms method starts off by calculating how many clock cycles has passed since the previous time this method was called. This method then goes looping through every alarm and decreasing the remaining clock cycles of each alarm by the number of clock cycles that lapsed since the previous time.

If the remaining time of an alarm reaches zero, the event associated with the alarm is triggered.

When a class wishes to add itself to the list of alarms, it is important for that class to implement the following public methods:
  • getIsEnabled: Return true if you want AlarmManager to process your alarm
  • getTicksBeforeExpiry: Return the number of clock cycles left before calling event
  • setTicksBeforeExpiry: Adjust number of clock cycles remaining with specified value
  • trigger: Alarm manager calls this method on your class when remaining clock cycles has reached 0
With all this information, we can now complete our  tape class:

function tape(alarmManager) {
  var myAlarmManager = alarmManager;
  var tapeData;
  var posInTape;
  var isEnabled = false;
  var ticksBeforeExpiry = 0;
  myAlarmManager.addAlarm(this);

  this.attachTape = function(file) {
       var reader = new FileReader();
       reader.onload = function(e) {
         var arrayBuffer = reader.result;
         tapeData = new Uint8Array(arrayBuffer);
         posInTape = 0x14;
         scheduleNextTrigger();
         alert("Tape attached");
       }
       reader.readAsArrayBuffer(file);

  }

  this.setMotorOn = function(bit) {
    isEnabled = (bit == 0) ? true : false;
  }

  function scheduleNextTrigger() {
    ticksBeforeExpiry = tapeData[posInTape] << 3;
    posInTape++;
  }

  this.getIsEnabled = function() {
    return isEnabled;
  }

  this.getTicksBeforeExpiry = function() {
    return ticksBeforeExpiry;
  }

  this.setTicksBeforeExpiry = function(ticks) {
    ticksBeforeExpiry = ticks;
  }

  this.trigger = function() {
    //trigger interrupt
    scheduleNextTrigger();
  }

}

When we create an instance of tape, we immediately add ourself to the list of alarms.

An interesting addition to our class is the public method setMotorOn. Our memory class should call this method each there is a write to memory location 1. This will be our cue to decide if our tape class should be running or not.

In the trigger method two things should basically happen: Trigger an interrupt and schedule the alarm. You will notice that trigger interrupt I have added as a comment. This is because at this point it is not completely clear how the interrupt functionality should work for this scenario. We will tackle this in the next blog.

In Summary

In this blog we started to implement tape emulation to our emulator.

We ended off with identifying the need to implement CIA interrupt functionality as one of the prerequisites for tape emulation.

Though not mentioned in this blog, for successful Tape emulation, the full Timer A and Timer B functionality of the CIA also needs to be implemented.

Thus, in the next bog, we will continue with implementing the Tape functionality and add the following emulation:

  • CIA interrupts
  • Timer A and Timer B functionality of the CIA
Till next time!


Tuesday 14 June 2016

Part 13: Implementing a workable keyboard


Foreword

In the previous blog we managed to simulate a single kepress. In this blog we will write code to actually interface with your physical keyboard.

By the end of this blog, you would be able to enter simple Basic programs and run it.

Trapping keys


We would like to encapsulate all the keyboard functionality into a class of its own. So, let us start with the plumbing first.

We first create a file Keyboard.js, hosting our keyboard class:

function keyboard() {
}

As with all our important classes we need to include this file in the head tag of index.html and create an instance of this class:

  ...
  <head>
    <title>6502 Emulator From Scratch</title>
    <script src="Memory.js"></script>
    <script src="Cpu.js"></script>
    <script src="Video.js"></script>
    <script src="Keyboard.js"></script>
  </head>
  ...
    <script language="JavaScript">
      var mykeyboard = new keyboard();
      var mymem = new memory(postInit);
      var mycpu = new cpu(mymem);
  ...




We are more or less done with the plumbing. Lets move on to implement the meat of our keyboard class.

We start off the implementation by asking the question: Does JavaScript provide us with a way to capture key strokes?

JavaScript indeed provide us with two events called, onkeydown and onkeyup. The names speaks for itself. When you press a key down, an onkeydown event will fire. When you release a key, an onkeyup event will fire.

The best place to define these two events in our emulator is within the body tag in our index.html:

<body onkeydown="mykeyboard.onkeydown(event)" onkeyup="mykeyboard.onkeyup(event)">

This assumes our keyboard class has the method onkeydown and onkeyup defined. Lets go about and implement skeletons for these two methods in our keyboard class:

function keyboard() {

 this.onkeydown = function(event) {
 }

 this.onkeyup = function(event) {
 }
}

Now the question on what code these two methods should contain. Basically what should happen is that in our onkeydown method we should store the keyevent for our emulator when it needs it. Obviously, in the onkeyup event we should remove the stored event since it would no longer be applicable for our emulator.

So, what do we need to store of the event? The event actually contains a very useful property that we can store, called keyCode. keyCode has the unshifted ASCII code of the key that fired the event. This means, for instance, if you hold down the "one key", it will register the code 49. If you are pressing the "one key" while holding the shift key, it will also register the code 49. All your alphabet letters will register the capital version of the applicable letter, irrespective if the shift key was down or not.

The unshifted ASCII code is perfect for our needs. If there is a shift key involved our scanning process will pick it up as two separate keypresses.

We will store all the keydown events within an array. With all this in mind, our keyboard class will look as follows:

function keyboard() {

  var keyarray = [];

  this.onkeydown = function(event) {
    if (event.keyCode == 32)
      event.preventDefault();

    if (keyarray.indexOf(event.keyCode) == -1)
      keyarray.push(event.keyCode);
  }

  this.onkeyup = function(event) {
    var ind = keyarray.indexOf(event.keyCode);
    keyarray.splice(ind,1);
  }

}

Let me quickly explain all the code. Obviously our array that stores the events is called keyarray which we start off as an empty array.

Next, lets zoom into the method onkeydown. The testing of keyCode 32 looks a bit odd, so let me explain. In my Firefox browser I actually found that pressing the space bar causes the browser window to scroll, so my emulator would indeed register a space, but I had to scroll back each time I typed a space. This if statement would fix that behaviour.

You will also see that after the keCode 32 check, I don't add the keyCode straight away to keyarray. This was also due to another side effect I found. While holding in a key, repeating keydown events fire. From the JavaScript documentation I found that this is mainly happening in Linux, but to be save, we would rather check if the code already exist in the array before adding it.

Finally, if we are sure the keyCode doesn't already exist in the array, we add it via a push. Push appends the keyCode to the end of the array, effectively growing the array by one element. That is one cool feature of JavaScript: Dynamic Arrays.

Next, lets discuss the onkeyUp event. In this event we remove the keyCode we previously added via the onkeydown event. The first line we ask JavaScript to find at which element number the relevant keyCode lives. We then remove the element with splice giving it the position and ordering it to only remove one element.

Emulating keypresses

Up to this point in time we are in a position to always know which key is down at any point in time. What remains to be done is to transfer this knowledge in way that our KERNEL ROM will understand. That is, giving the KERNEL what it wants when it reads memory location DC01h. We do this by implementing the following method in out keyboard class:

  this.getColumnByte = function(rowByte) {
    var rowArray = [0,0,0,0,0,0,0,0];
    rowByte = ~rowByte;
    rowByte = rowByte & 0xff;
    var i;
    for (i = 0; i < keyarray.length; i++) {
      var scanCode = getScanCode(keyarray[i]);
      var rowNum = (scanCode & 0x38) >> 3;
      rowArray[rowNum] = rowArray[rowNum] | (1 << (scanCode & 7));
    }
    var resultByte = 0;
    for (i = 0; i < 8; i++) {
      var currentRowEnabled = ((1 << i) & rowByte) != 0;
      if (currentRowEnabled)
        resultByte = resultByte | rowArray[i];
    }
    resultByte = ~resultByte;
    resultByte = resultByte & 0xff;
    return resultByte;
  }


As you can see we are passing a parameter rowByte to this method. rowByte is effectively the contents of memory location DC00h.

Two major things are happening in this method: It starts/ends with negations (~), and the use of scan codes. I will spend some time now explaining each of these.

Firstly, why all these negations? In the previous blog we saw that with the keyboard matrix, a zero means activated and a one means the opposite. This logic makes bit operations very difficult. To deal with this, we negate the rowByte in the beginning of the method. From this point onwards a one means active and make bit operations easier. Before we exit the method, we negate the result so that the byte returned follows the zero-active logic.

Next, lets discuss scan codes. Firstly, what is a scan code? A scan code is way to refer to a particular key in the keyboard matrix with a single number, instead of numbers, row and column. Scan codes simplifies lookups.

So, how do you determine the scan code of a key? Let us have a look again at the keyboard matrix of the C64:



Bit#0
$01,$FE
Bit#1
$02,$FD
Bit#2
$04,$FB
Bit#3
$08,$F7
Bit#4
$10,$EF
Bit#5
$20,$DF
Bit#6
$40,$BF
Bit#7
$80,$7F
Bit#0
$01,$FE
Insert/DeleteReturncursor left/rightF7F1F3F5cursor up/down
Bit#1
$02,$FD
3WA4ZSEleft Shift
Bit#2
$04,$FB
5RD6CFTX
Bit#3
$08,$F7
7YG8BHUV
Bit#4
$10,$EF
9IJ0MKON
Bit#5
$20,$DF
+ (plus)PL– (minus). (period): (colon)@ (at), (comma)
Bit#6
$40,$BF
£ (pound)* (asterisk); (semicolon)Clear/Homeright Shift (Shift Lock)= (equal)↑ (up arrow)/ (slash)
Bit#7
$80,$7F
1← (left arrow)Control2SpaceCommodoreQRun/Stop

Scan code numbering start at the first row (bit 0). In that row it starts counting from 0 and count to 7. We then go to the next row and count from 8 to 15. This process is followed for every row.

To convert a scancode back to a row/column value is very easy. The least three bits of the scan code is the column number and the upper three bits is the row.

With all this background, we can discuss the getColumnByte method.

The method begins with declaring rowArray. Strickly speaking, this is a two dimensional array representing the keyboard matrix. The eight bits of each element gives you the second dimension.

We then loop through all elements of the keyarray. Before we can do anything useful with an element from the keyarray, we need to convert it to a scan code. The getScanCode method takes care of this for us. The getScanCode method is basically a big case statement returning a scanCode, given an ascii code.

The remaining part of the loop set the applicable bit in the rowarray matrix for the given scan code.

Next, the rowByte is examined to determine which rows are activated. The values of all active rows are taken from the rowArray and or'ed together. The result for this OR operation is the value we should pass back.

What remains to be done is to let the Memory class make use of the keyboard class. To do this we should first inject a keyboard instance into the memory class as follows:

function memory(allDownloadedCallback, keyboard)

{
  var mainMem = new Uint8Array(65536);
  var basicRom = new Uint8Array(8192);
  var kernalRom = new Uint8Array(8192);
  var charRom = new Uint8Array(4192);
  var outstandingDownloads = 3;
  var simulateKeypress = false;
  var keyboardInstance = keyboard;
...
}

Of course, we should adjust index.html as well:

    <script language="JavaScript">
      var mykeyboard = new keyboard();
      var mymem = new memory(postInit,mykeyboard);
      var mycpu = new cpu(mymem);
...

Finally, lets adjust the readMem method in the memory class:

  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if (address == 0xdc01) {
      return keyboardInstance.getColumnByte(mainMem[0xdc00]);
    }
    return mainMem[address];
  }

Given the emulated keyboard a Test Run

We are now ready to give give our emulated keyboard a Test run.

My test run did not start off so well. Initially my emulator didn't accept any keystrokes. After a bit of playing I actually found that you need to click on the emulator screen before it would accept any keystrokes.

It was as if our emulator web page was loosing focus for some reason.

Closer investigation yielded that the problem is caused when we click the run button. At that point the run button has focus. Part of the stuff that is happening when we click the run button, is to actually disable it. What solve this issue is to actually let the run button loose focus before disabling it:

      function startEm() {
        document.getElementById("btnStep").disabled = true;
        document.getElementById("btnRun").blur();
        document.getElementById("btnRun").disabled = true;
        document.getElementById("btnStop").disabled = false;
        var myBreak = document.getElementById("breakpoint");
        breakpoint = parseInt(myBreak.value, 16);
        running = true;
        myTimer = setInterval(runBatch, 20);
      }

One should now be able to enter some BASIC programs and run it. I must admit, I haven't implemented all the keys. So, at the moment for some basic programs you need to extend the getScanCode method. The keys that are implemented currently are as follows:


  • Letters
  • Digits
  • Space bar
  • shift key
  • Return key
Here is one of my sessions:


In Summary

In this blog we managed to interface to a physical keyboard. With this functionality we are now able to enter simple basic programs and run it.

In the next blog we will be exploring Tape emulation. This will be the blog in series of blogs where will attempt to emulate a game loaded from tape.

Till next time!

Sunday 5 June 2016

Part 12: Simulating a key press

Foreword

In the previous Blog we managed to get the flashing cursor to work in our emulator.

In this blog we will start to tackle the emulation of the keyboard.

To start off, we will cover some theory on how the C64 is interfaced to the system. Afterwards, we will see if we can put the theory to the test and simulate a keypress in our emulator.

This blog will unfortunately not end off with the emulator integrating with your keyboard.  I feel that this blog already contains a lot of overwhelming technical detail, so I decided to leave the integration to a physical keyboard for the next Blog.

Enjoy!

Some Keyboard Theory

The keys on the C64 keyboard is arranged in a matrix that looks as follows:


To determine if a particular key is pressed, a process called keyboard scanning is followed.

With keyboard scanning a particular row is pulled low (logical 0) and each column is examined in turn to see which ones are pulled low. For each in key in that row that is pressed the associated column will register a zero.

Needles to say, the above process is repeated for each and every column.

How does the keyboard interface to the CIA chips? Again, let us visit a schematic of the C64 as we did in the previous post:

As you can see the keyboard connector connects to CIA 1 via port A and port B.

It is not very easy to map this diagram to the scan table earlier in this section, because of different numbering. The following diagram makes understanding the mapping easier:


I found this table at http://sta.c64.org/cbm64kbdlay.html

This table assigns a bit number to each row/column, which will make out task easier.

Simulating a key press

Next, let us see if we can simulate a keypress in our emulator.

I will simulate pressing the 8 key. From the scan-code table we see that key 8 is row bit 3 and column bit 3.

How do we simulate this? First let us see what is involved during a keyboard scan:

  • Kernel ROM code write the particular row to pull low to address DC00h
  • Kernel ROM reads address DC01h and determines which columns are pulled low.
So, we need to trick KERNEL ROM a bit when it accesses addresses DC00h and DC01h. From these two addresses we must actually check when a read is done on DC01h.

So, what do we do if we detect a read on address DC01h? Firstly we check address DC00h to find which row the KERNEL ROM intended to pull low. Remember, for now we are only interested in simulating pressing an 8. So, we need to be alert only when the KERNEL ROM pulls done bit 3.

So, we need to check if address DC00 has value F7 (e.g. bit 3 masked), we need to return F7 as the result of a DC01h address read. For all other values of DC00 we will return a FFh for a DC01h read.

Lets get coding. The place to implement this functionality is in the readMem method in the Memory class:

  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if (address == 0xdc01) {
      if (mainMem[0xdc00] == 0xf7)
        return 0xf7;
      else
        return 0xff;
    }    return mainMem[address];
  }


With this implementation, a key down will be simulated from the time we start our emulator. I cannot tell for sure if this will effect any initialisation process.

To avoid any potential issues during bootup, we should perhaps postpone the simulated keypress until we know the boot process is completed.

So, what what I have in mind is to only start the simulated keypress after 6000000 CPU cycles (e.g. 6 seconds).

In the runBatch method we have a handle on the CPU cycle count. So, we need a way for the runBatch method to inform the Memory class that it can start to simulate a keypress.

For this we start off by implementing a private variable simulateKeypress in the memory class:

  var mainMem = new Uint8Array(65536);
  var basicRom = new Uint8Array(8192);
  var kernalRom = new Uint8Array(8192);
  var charRom = new Uint8Array(4192);
  var outstandingDownloads = 3;
  var simulateKeypress = false;

And we surface this variable to the runBatch method with a public method:

  this.setSimulateKeypress = function () {
    simulateKeypress = true;
  }


In the readMem method we should now consider this private variable before simulating a kepress:

  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if (address == 0xdc01) {
      if ((mainMem[0xdc00] == 0xf7) & simulateKeypress)
        return 0xf7;
      else
        return 0xff;
    }    
    return mainMem[address];
  }


Finally, within our runBatch method, we should trigger the simulation after 6 seconds:

        while (mycpu.getCycleCount() < targetCycleCount) { 
          mycpu.step();
          if (mycpu.getCycleCount() > 6000000)
            mymem.setSimulateKeypress();        ...
        }

We are now ready to give our changes a test run.

When running our code changes, an 8 doesn't appear as we expect. What went wrong?

Lets have a look at the first couple of lines of the scan keyboard routine:

; scan keyboard

EA87   A9 00      LDA #$00
EA89   8D 8D 02   STA $028D
EA8C   A0 40      LDY #$40
EA8E   84 CB      STY $CB
EA90   8D 00 DC   STA $DC00
EA93   AE 01 DC   LDX $DC01
EA96   E0 FF      CPX #$FF
EA98   F0 61      BEQ $EAFB
EA9A   A8         TAY
EA9B   A9 81      LDA #$81
EA9D   85 F5      STA $F5

Something strange that pops out here is the writing of the value 0 to memory location DC00. In effect this will pull all rows low.

Why would one want to do that? After doing some searching on the Internet, it appears that this is just a quick check to see if a key was press at all.

Well. this is a scenario we haven't included in our code, so lets do it:

  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if (address == 0xdc01) {
      if (((mainMem[0xdc00] == 0xf7) | (mainMem[0xdc00] == 0x0)) & simulateKeypress)
        return 0xf7;
      else
        return 0xff;
    }    
    return mainMem[address];
  }


This time it worked!

Lets be a bit naughty and simulating one of the repeater keys like the space bar. From the table we see that the spacebar has row code 7f and column code ef. We make the following adjustments and rerun:

  this.readMem = function (address) {
    if ((address >= 0xa000) & (address <=0xbfff))
      return basicRom[address & 0x1fff];
    else if ((address >= 0xe000) & (address <=0xffff))
      return kernalRom[address & 0x1fff];
    else if (address == 0xdc01) {
      if (((mainMem[0xdc00] == 0x7f) | (mainMem[0xdc00] == 0x0)) & simulateKeypress)
        return 0xef;
      else
        return 0xff;
    }
    return mainMem[address];
  }


As expected, our cursor continues to move while spaces are typed, eventually scrolling the welcome message off the screen.

In Summary

In this Blog we managed to simulate a simple key press.

In the next blog we will integrate our emulator with you keyboard, so you will be able to enter some Basic Programs in it an tun them.

Till next Time!