/ MCUME_teensy / teensy8086 / i8253.cpp
i8253.cpp
  1  #include <stdint.h>
  2  #include <string.h>
  3  #include <Arduino.h>
  4  
  5  #ifdef MEGA
  6    #include <TimerOne.h>
  7  #else
  8  IntervalTimer myTimer;
  9  #endif
 10  
 11  #define PIT_MODE_LATCHCOUNT  0
 12  #define PIT_MODE_LOBYTE 1
 13  #define PIT_MODE_HIBYTE 2
 14  #define PIT_MODE_TOGGLE 3
 15  
 16  
 17  struct i8253_s {
 18    uint16_t chandata[3];
 19    uint8_t accessmode[3];
 20    uint8_t bytetoggle[3];
 21    uint32_t effectivedata[3];
 22    float chanfreq[3];
 23    uint8_t active[3];
 24    uint16_t counter[3];
 25  } i8253;
 26  
 27  volatile uint8_t timerTick = 0;
 28  
 29  void timer_isr() {
 30    timerTick = 1;
 31  }
 32  
 33  void out8253 (uint16_t portnum, uint8_t value) {
 34    uint8_t curbyte;
 35    portnum &= 3;
 36    switch (portnum) {
 37        case 0:
 38        case 1:
 39        case 2: //channel data
 40          if ( (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0;
 41          else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1;
 42          if (curbyte == 0) { //low byte
 43              i8253.chandata[portnum] = (i8253.chandata[portnum] & 0xFF00) | value;
 44            }
 45          else {   //high byte
 46              i8253.chandata[portnum] = (i8253.chandata[portnum] & 0x00FF) | ( (uint16_t) value << 8);
 47            }
 48          if (i8253.chandata[portnum] == 0) i8253.effectivedata[portnum] = 65536;
 49          else i8253.effectivedata[portnum] = i8253.chandata[portnum];
 50          i8253.active[portnum] = 1;
 51          if (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1;
 52          //i8253.chanfreq[portnum] = (float) ( (uint32_t) ( ( (float) 1193182.0 / (float) i8253.effectivedata[portnum]) * (float) 1000.0) );
 53          //Serial.print("period "); Serial.println((uint32_t) ((float)1000000.0 / ( ( (float) 1193182.0 / (float) i8253.effectivedata[portnum]))));
 54          if (portnum == 0) {
 55            uint32_t period;
 56            period = (uint32_t) ((float)1000000.0 / ( ( (float) 1193182.0 / (float) i8253.effectivedata[portnum])));
 57  #ifdef MEGA
 58            if (period < 4000) period = 4000; //limit to 250 Hz, or the emulator just can't keep up on a Mega
 59            //Serial.println((float)1000000.0 / (float)period);
 60            Timer1.attachInterrupt(timer_isr, period);
 61  #else
 62            myTimer.begin(timer_isr, period);
 63  #endif
 64          }
 65          break;
 66        case 3: //mode/command
 67          i8253.accessmode[value>>6] = (value >> 4) & 3;
 68          if (i8253.accessmode[value>>6] == PIT_MODE_TOGGLE) i8253.bytetoggle[value>>6] = 0;
 69          break;
 70      }
 71  }
 72  
 73  uint8_t in8253 (uint16_t portnum) {
 74    uint8_t curbyte;
 75    portnum &= 3;
 76    switch (portnum) {
 77        case 0:
 78        case 1:
 79        case 2: //channel data
 80          if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0;
 81          else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1;
 82          if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0;
 83          else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1;
 84          if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) ) i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1;
 85          if (curbyte == 0) { //low byte
 86            if (i8253.counter[portnum] < 10) i8253.counter[portnum] = i8253.chandata[portnum];
 87            i8253.counter[portnum] -= 10;
 88              return ( (uint8_t) i8253.counter[portnum]);
 89            }
 90          else {   //high byte
 91              return ( (uint8_t) (i8253.counter[portnum] >> 8) );
 92            }
 93          break;
 94      }
 95    return (0);
 96  }
 97  
 98  void init8253() {
 99    memset (&i8253, 0, sizeof (i8253) );
100  #ifdef MEGA
101    Timer1.initialize(54925);
102    Timer1.attachInterrupt(timer_isr, 54925);
103  #else
104    myTimer.begin(timer_isr, 54925);
105  #endif
106    //set_port_write_redirector (0x40, 0x43, &out8253);
107    //set_port_read_redirector (0x40, 0x43, &in8253);
108  }
109