Top secrets sources NedoPC pentevo

Rev

Rev 656 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/twi.h>

#include "pins.h"
#include "mytypes.h"
#include "main.h"
#include "zx.h"
#include "rtc.h"
#include "ps2.h"
#include "version.h"
#include "rs232.h"

//if want Log than comment next string
#undef LOGENABLE

volatile UBYTE gluk_regs[14];

//stop transmit
static void tw_send_stop(void)
{
        TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWSTO);
        //wait for flag
//      while ( (TWCR&_BV(TWSTO))!=0 );
//      _delay_us(20); //4mks for PCF8583
}

static UBYTE tw_send_start(void)
{
        //start transmit
        TWCR =_BV(TWINT)|_BV(TWSTA)|_BV(TWEN);

        //wait for flag
        while ( (TWCR&_BV(TWINT))==0 );
//      while ( TWCR & (1<<TWSTA) );

//#ifdef LOGENABLE
//      char log_reset_type[] = "TWS..[..]..\r\n";
//      UBYTE b = TWSR;
//      log_reset_type[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_reset_type[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      b=TWCR;
//      log_reset_type[6] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_reset_type[7] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      b=TWDR;
//      log_reset_type[9] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_reset_type[10] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      to_log(log_reset_type);
//#endif
        //return status
   return TW_STATUS;
}

static UBYTE tw_send_addr(UBYTE addr)
{
        //set address
        TWDR = addr;

        //enable transmit
        TWCR = _BV(TWINT)|_BV(TWEN);

        //wait for end transmit
        while ( (TWCR &_BV(TWINT))==0 );

//#ifdef LOGENABLE
//      char log_tw[] = "TWA..[..]..\r\n";
//      UBYTE b = TWSR;
//      log_tw[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_tw[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      b=TWCR;
//      log_tw[6] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_tw[7] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      log_tw[9] = ((addr >> 4) <= 9 )?'0'+(addr >> 4):'A'+(addr >> 4)-10;
//      log_tw[10] = ((addr & 0x0F) <= 9 )?'0'+(addr & 0x0F):'A'+(addr & 0x0F)-10;
//      to_log(log_tw);
//#endif
        //return status
   return TW_STATUS;
}

static UBYTE tw_send_data(UBYTE data)
{
        //set data
        TWDR = data;

        //enable transmit
        TWCR = _BV(TWINT)|_BV(TWEN);

        //wait for end transmit
        while ( (TWCR&_BV(TWINT))==0 );

//#ifdef LOGENABLE
//      char log_tw[] = "TWW..[..]..\r\n";
//      UBYTE b = TWSR;
//      log_tw[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_tw[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      b=TWCR;
//      log_tw[6] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_tw[7] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      log_tw[9] = ((data >> 4) <= 9 )?'0'+(data >> 4):'A'+(data >> 4)-10;
//      log_tw[10] = ((data & 0x0F) <= 9 )?'0'+(data & 0x0F):'A'+(data & 0x0F)-10;
//      to_log(log_tw);
//#endif
        //return status
   return TW_STATUS;
}

static UBYTE tw_read_data(UBYTE* data)
{
        //enable
        TWCR = _BV(TWINT)|_BV(TWEN);

        //wait for flag set
        while ( (TWCR&_BV(TWINT))==0 );

//#ifdef LOGENABLE
//      char log_tw[] = "TWR..[..]..\r\n";
//      UBYTE b = TWSR;
//      log_tw[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_tw[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      b=TWCR;
//      log_tw[6] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
//      log_tw[7] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
//      log_tw[9] = ((TWDR >> 4) <= 9 )?'0'+(TWDR >> 4):'A'+(TWDR >> 4)-10;
//      log_tw[10] = ((TWDR & 0x0F) <= 9 )?'0'+(TWDR & 0x0F):'A'+(TWDR & 0x0F)-10;
//      to_log(log_tw);
//#endif
        //get data
        *data = TWDR;

        //return status
   return TW_STATUS;
}

static UBYTE bcd_to_hex(UBYTE data)
{
        //convert BCD to HEX
        return  (UBYTE)(data>>4)*10 + (UBYTE)(data&0x0F);
}

static UBYTE hex_to_bcd(UBYTE data)
{
        //convert HEX to BCD
        return  (UBYTE)((data/10)<<4) + (UBYTE)(data%10);
}

static UBYTE days_of_months()
{
        //return number of days in month
        static const UBYTE days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
        UBYTE tmp = gluk_regs[GLUK_REG_MONTH]-1;

        if ( tmp > sizeof(days)-1 ) tmp = 0; //check range

        tmp = days[tmp];

        //check leap-year
        if ( (tmp == 28) && ( ( gluk_regs[GLUK_REG_YEAR]&0x03 ) == 0 ) ) tmp++;

        return tmp;
}

static UBYTE read_eeprom(UBYTE offset)
{
        UWORD ptr = gluk_regs[GLUK_REG_A];
        ptr = (ptr<<4) + (0x0F&offset);

        //wait for eeprom
        eeprom_busy_wait();

        return eeprom_read_byte((UBYTE*)ptr);
}

static void write_eeprom(UBYTE offset, UBYTE data)
{
        UWORD ptr = gluk_regs[GLUK_REG_A];
        ptr = (ptr<<4) + (0x0F&offset);

        //wait for eeprom
        eeprom_busy_wait();

        eeprom_write_byte ((UBYTE*)ptr, data);
}

void rtc_init(void)
{
        //SCL frequency = CPU clk/ ( 16 + 2* (TWBR) * 4^(TWPS) )
        // 11052000 / (16 + 2*48 ) = 98678,5Hz (100000Hz recommended for PCF8583)
        TWSR = 0;
        TWBR = 48;
        TWAR = 0; //disable address match unit

        //reset RTC
        //write 0 to control/status register [0] on PCF8583
        rtc_write(0, 0);

        //set Gluk clock registers
        gluk_init();
        if ( gluk_regs[GLUK_REG_SEC] == 0 ) gluk_init();

        //restore mode register from NVRAM (CAPS LED off on init)
        modes_register = rtc_read(RTC_COMMON_MODE_REG) & ~(MODE_CAPSLED);

        //set modes on fpga
        zx_set_config(0);
}

void rtc_write(UBYTE addr, UBYTE data)
{
        //set address
        if ( tw_send_start() & (TW_START|TW_REP_START) )
        {
                if ( tw_send_addr(RTC_ADDRESS|TW_WRITE) == TW_MT_SLA_ACK )
                {
                        if ( tw_send_data(addr) == TW_MT_DATA_ACK )
                        {
                                //write data
                                tw_send_data(data);
                        }
                }
        }
        tw_send_stop();
}

UBYTE rtc_read(UBYTE addr)
{
        UBYTE ret = 0;

        //set address
        if ( tw_send_start() & (TW_START|TW_REP_START) )
        {
                if ( tw_send_addr(RTC_ADDRESS|TW_WRITE) == TW_MT_SLA_ACK )
                {
                        if ( tw_send_data(addr) == TW_MT_DATA_ACK )
                        {
                                //read data
                                if ( tw_send_start() == TW_REP_START )
                                {
                                        if ( tw_send_addr(RTC_ADDRESS|TW_READ) == TW_MR_SLA_ACK )
                                        {
                                                tw_read_data(&ret);
                                        }
                                }
                        }
                }
        }
        tw_send_stop();
        return ret;
}

void gluk_init(void)
{
        UBYTE tmp;
        //default values
        gluk_regs[GLUK_REG_A] = GLUK_A_INIT_VALUE;
        gluk_regs[GLUK_REG_B] = GLUK_B_INIT_VALUE;
        gluk_regs[GLUK_REG_C] = GLUK_C_INIT_VALUE;
        gluk_regs[GLUK_REG_D] = GLUK_D_INIT_VALUE;

        //setup

        //read month and day of week
        tmp = rtc_read(6);
        gluk_regs[GLUK_REG_MONTH] = bcd_to_hex(0x1F&tmp);
        tmp = (tmp>>5);
        //PC8583 dayweek 0..6 => DS12788 dayweek 1..7
        gluk_regs[GLUK_REG_DAY_WEEK] = (tmp>6)?1:tmp+1;

        //read year and day of month
        tmp = rtc_read(5);
        gluk_regs[GLUK_REG_DAY_MONTH] = bcd_to_hex(0x3F&tmp);
        gluk_regs[GLUK_REG_YEAR] = tmp>>6;
        tmp = rtc_read(RTC_YEAR_ADD_REG);
        if ( (tmp&0x03) > gluk_regs[GLUK_REG_YEAR] )
        {
                //count of year over - correct year
                tmp += 4;
                if ( tmp >= 100 ) tmp = 0;
        }
        gluk_regs[GLUK_REG_YEAR] += tmp&0xFC;
        rtc_write(RTC_YEAR_ADD_REG,gluk_regs[GLUK_REG_YEAR]); //save year

        //read time
        gluk_regs[GLUK_REG_HOUR] = bcd_to_hex(0x3F&rtc_read(4)); //TODO 12/24 format
        gluk_regs[GLUK_REG_MIN] = bcd_to_hex(rtc_read(3));
        gluk_regs[GLUK_REG_SEC] = bcd_to_hex(rtc_read(2));
}

void gluk_inc(void)
{
        if ( ++gluk_regs[GLUK_REG_SEC] >= 60 )
        {
                gluk_regs[GLUK_REG_SEC] = 0;
                if ( ++gluk_regs[GLUK_REG_MIN] >= 60 )
                {
                        gluk_regs[GLUK_REG_MIN] = 0;
                        if ( ++gluk_regs[GLUK_REG_HOUR] >= 24 )
                        {
                                gluk_regs[GLUK_REG_HOUR] = 0;
                                if ( ++gluk_regs[GLUK_REG_DAY_WEEK] > 7  )
                                {
                                        gluk_regs[GLUK_REG_DAY_WEEK] = 1;
                                }
                                if ( ++gluk_regs[GLUK_REG_DAY_MONTH] > days_of_months() )
                                {
                                        gluk_regs[GLUK_REG_DAY_MONTH] = 1;
                                        if ( ++gluk_regs[GLUK_REG_MONTH] > 12 )
                                        {
                                                gluk_regs[GLUK_REG_MONTH] = 1;
                                                if( ++gluk_regs[GLUK_REG_YEAR] >= 100 )
                                                {
                                                        gluk_regs[GLUK_REG_YEAR] = 0;
                                                }
                                        }
                                }
                        }
                }
        }

        //set update flag
        gluk_regs[GLUK_REG_C] |= GLUK_C_UPDATE_FLAG;

//#ifdef LOGENABLE
//{
//      char log_int_rtc[] = "00.00.00\r\n";
//      log_int_rtc[0] = '0' + gluk_regs[GLUK_REG_HOUR]/10;
//      log_int_rtc[1] = '0' + gluk_regs[GLUK_REG_HOUR]%10;
//      log_int_rtc[3] = '0' + gluk_regs[GLUK_REG_MIN]/10;
//      log_int_rtc[4] = '0' + gluk_regs[GLUK_REG_MIN]%10;
//      log_int_rtc[6] = '0' + gluk_regs[GLUK_REG_SEC]/10;
//      log_int_rtc[7] = '0' + gluk_regs[GLUK_REG_SEC]%10;
//      to_log(log_int_rtc);
//}
//#endif
}

UBYTE gluk_get_reg(UBYTE index)
{
        UBYTE tmp;

        if( index < sizeof(gluk_regs)/sizeof(gluk_regs[0]) )
        {
                //clock registers from array
                tmp = gluk_regs[index];
                if ( ( index<10 ) && ( (gluk_regs[GLUK_REG_B]&GLUK_B_DATA_MODE) == 0 ) )
                {
                        //clock registers mast be in BCD if HEX-bit not set in reg B
                        tmp = hex_to_bcd(tmp);
                }

                if ( index == GLUK_REG_C )
                {
                        //clear update flag
                        gluk_regs[GLUK_REG_C] &= ~GLUK_C_UPDATE_FLAG;

                        //3 bit - SD card detect
                        //2 bit - SD WRP detect
                        tmp |= (((~SD_PIN)&((1<<SDWRP)|(1<<SDDET)))>>2);

                        //0 - bit numlock led status on read
                    if ( (PS2KEYBOARD_LED_NUMLOCK&modes_register)!=0 )
                        {
                                tmp |= GLUK_C_NUM_LED_FLAG;
                        }
                        else
                        {

                                tmp &= ~GLUK_C_NUM_LED_FLAG;
                        }
                }

                if ( index == GLUK_REG_D )
                {
                        //return keyboard statuses
                        tmp &= ~(KB_LCTRL_MASK|KB_RCTRL_MASK|KB_LALT_MASK|KB_RALT_MASK|KB_LSHIFT_MASK|KB_RSHIFT_MASK|KB_F12_MASK);
                        tmp |= (kb_ctrl_status&(KB_LCTRL_MASK|KB_RCTRL_MASK|KB_LALT_MASK|KB_RALT_MASK|KB_LSHIFT_MASK|KB_RSHIFT_MASK|KB_F12_MASK));
                }
        }
        else
        {
                if ( index >= 0xF0 )
                {
                        if ( (gluk_regs[GLUK_REG_C]&GLUK_C_EEPROM_FLAG)!=0 )
                        {
                                //read from eeprom
                                tmp = read_eeprom(index);
                        }
                        else
                        {
                                //read version
                                tmp = GetVersionByte( index&0x0F );
                        }
                }
                else
                {
                        //other from nvram
                        //- on PCF8583 nvram started from #10
                        //- on 512vi1[DS12887] nvram started from #0E
                        tmp = rtc_read( (index/*&0x3F*/)+2 );
                }
        }

#ifdef LOGENABLE
        {
                char log_gs[] = "GR[..]..\r\n";
                UBYTE b = index;
                log_gs[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
                log_gs[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
                b = tmp;
                log_gs[6] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
                log_gs[7] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
                to_log(log_gs);
        }
#endif
        return tmp;
}

void gluk_set_reg(UBYTE index, UBYTE data)
{
#ifdef LOGENABLE
        char log_gs[] = "GS[..]..\r\n";
        UBYTE b = index;
        log_gs[3] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
        log_gs[4] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
        b=data;
        log_gs[6] = ((b >> 4) <= 9 )?'0'+(b >> 4):'A'+(b >> 4)-10;
        log_gs[7] = ((b & 0x0F) <= 9 )?'0'+(b & 0x0F):'A'+(b & 0x0F)-10;
        to_log(log_gs);
#endif

        if( index < sizeof(gluk_regs)/sizeof(gluk_regs[0]) )
        {
                if ( index<10 )
                {
                        //write to clock registers
                        if ( (gluk_regs[GLUK_REG_B]&GLUK_B_DATA_MODE) == 0 )
                        {
                                //array of registers must be in Hex, but data in BCD if HEX-bit not set in reg B
                                data = bcd_to_hex(data);
                        }
                        gluk_regs[index] = data;

                        //write to nvram if need
                        switch( index )
                        {
                                case GLUK_REG_SEC:
                                        if( data <= 59 ) rtc_write(2, hex_to_bcd(data/*gluk_regs[GLUK_REG_SEC]*/));
                                        break;
                                case GLUK_REG_MIN:
                                        if( data <= 59) rtc_write(3, hex_to_bcd(data/*gluk_regs[GLUK_REG_MIN]*/));
                                        break;
                                case GLUK_REG_HOUR:
                                        if( data <= 23) rtc_write(4, 0x3F&hex_to_bcd(data/*gluk_regs[GLUK_REG_HOUR]*/));
                                        break;
                                case GLUK_REG_MONTH:
                                case GLUK_REG_DAY_WEEK:
                                        if( ( gluk_regs[GLUK_REG_DAY_WEEK]-1 <= 6 ) &&
                                                ( gluk_regs[GLUK_REG_MONTH] > 0 ) &&
                                                ( gluk_regs[GLUK_REG_MONTH] <= 12 ) )
                                        {
                                                //DS12788 dayweek 1..7 => PC8583 dayweek 0..6
                                                rtc_write(6, ((gluk_regs[GLUK_REG_DAY_WEEK]-1)<<5)+(0x1F&hex_to_bcd(gluk_regs[GLUK_REG_MONTH])));
                                        }
                                        break;
                                case GLUK_REG_YEAR:
                                        rtc_write(RTC_YEAR_ADD_REG, gluk_regs[GLUK_REG_YEAR]);
                                case GLUK_REG_DAY_MONTH:
                                        rtc_write(5, (gluk_regs[GLUK_REG_YEAR]<<6)+(0x3F&hex_to_bcd(gluk_regs[GLUK_REG_DAY_MONTH])));
                                        break;
                        }
                }
                else
                {
                        switch( index )
                        {
                                case GLUK_REG_A:
                                        //EEPROM address
                                        gluk_regs[GLUK_REG_A]=data;
                                        break;

                                case GLUK_REG_B:
                                        //BCD or Hex mode set
                                        gluk_regs[GLUK_REG_B]=(data&GLUK_B_DATA_MODE)|GLUK_B_INIT_VALUE;
                                        break;

                                case GLUK_REG_C:
                                        if ( (data&GLUK_C_CLEAR_LOG_FLAG) != 0 )
                                        {
                                                //clear PS2 keyboard log
                                                ps2keyboard_reset_log();
                                        }
                                        if ( (data&GLUK_C_CAPS_LED_FLAG) != (gluk_regs[GLUK_REG_C]&GLUK_C_CAPS_LED_FLAG) )
                                        {
                                                //switch state of CAPS LED on PS2 keyboard
                                                gluk_regs[GLUK_REG_C] = gluk_regs[GLUK_REG_C]^GLUK_C_CAPS_LED_FLAG;
                                                modes_register = modes_register^MODE_CAPSLED;
                                                //set led on keyboard
                                                ps2keyboard_send_cmd(PS2KEYBOARD_CMD_SETLED);
                                        }
                                        if ( (data&GLUK_C_EEPROM_FLAG) != (gluk_regs[GLUK_REG_C]&GLUK_C_EEPROM_FLAG) )
                                        {
                                                //switch EEPROM mode
                                                gluk_regs[GLUK_REG_C] = gluk_regs[GLUK_REG_C]^GLUK_C_EEPROM_FLAG;
                                        }
                                        break;
                        }
                }
        }
        else
        {
                if ( index >= 0xF0 )
                {
                        if ( (gluk_regs[GLUK_REG_C]&GLUK_C_EEPROM_FLAG)!=0 )
                        {
                                //write to eeprom
                                write_eeprom(index, data);
                        }
                        else
                        {
                                //set version data type
                                SetVersionType( data );
                        }
                }
                else
                {
                        //write to nvram
                        //- on PCF8583 nvram started from #10
                        //- on 512vi1[DS12887] nvram started from #0E
                        rtc_write( (index/*&0x3F*/)+2, data);
                }
        }
}