#include "AT91SAM7S256.h" #include #include #include "hardware.h" #include "osd.h" #include "user_io.h" #include "cdc_control.h" #include "usb.h" #include "debug.h" #include "keycodes.h" #include "ikbd.h" #include "fat.h" #define BREAK 0x8000 extern fileTYPE file; extern char s[40]; typedef enum { EMU_NONE, EMU_MOUSE, EMU_JOY0, EMU_JOY1 } emu_mode_t; static emu_mode_t emu_mode = EMU_NONE; static unsigned char emu_state = 0; static long emu_timer; #define EMU_MOUSE_FREQ 5 static unsigned char core_type = CORE_TYPE_UNKNOWN; static char core_type_8bit_with_config_string = 0; static unsigned char adc_state = 0; AT91PS_ADC a_pADC = AT91C_BASE_ADC; AT91PS_PMC a_pPMC = AT91C_BASE_PMC; static char caps_lock_toggle = 0; static void PollOneAdc() { static unsigned char adc_cnt = 0xff; // fetch result from previous run if(adc_cnt != 0xff) { unsigned int result; // wait for end of convertion while(!(AT91C_BASE_ADC->ADC_SR & (1 << (4+adc_cnt)))); switch (adc_cnt) { case 0: result = AT91C_BASE_ADC->ADC_CDR4; break; case 1: result = AT91C_BASE_ADC->ADC_CDR5; break; case 2: result = AT91C_BASE_ADC->ADC_CDR6; break; case 3: result = AT91C_BASE_ADC->ADC_CDR7; break; } if(result < 128) adc_state |= (1< 128) adc_state &= ~(1<ADC_CHER = 1 << (4+adc_cnt); // Start conversion AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; } static void InitADC(void) { // Enable clock for interface AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_ADC; // Reset AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; AT91C_BASE_ADC->ADC_CR = 0x0; // Set maximum startup time and hold time AT91C_BASE_ADC->ADC_MR = 0x0F1F0F00 | AT91C_ADC_LOWRES_8_BIT; // make sure we get the first values immediately PollOneAdc(); PollOneAdc(); PollOneAdc(); PollOneAdc(); } // poll one adc channel every 25ms static void PollAdc() { static long adc_timer = 0; if(CheckTimer(adc_timer)) { adc_timer = GetTimer(25); PollOneAdc(); } } void user_io_init() { InitADC(); ikbd_init(); } unsigned char user_io_core_type() { return core_type; } char user_io_create_config_name(char *s) { char *p = user_io_8bit_get_string(0); // get core name if(p && p[0]) { strcpy(s, p); while(strlen(s) < 8) strcat(s, " "); strcat(s, "CFG"); return 0; } return 1; } char user_io_is_8bit_with_config_string() { return core_type_8bit_with_config_string; } void user_io_detect_core_type() { EnableIO(); core_type = SPI(0xff); DisableIO(); if((core_type != CORE_TYPE_DUMB) && (core_type != CORE_TYPE_MINIMIG) && (core_type != CORE_TYPE_PACE) && (core_type != CORE_TYPE_MIST) && (core_type != CORE_TYPE_8BIT)) core_type = CORE_TYPE_UNKNOWN; switch(core_type) { case CORE_TYPE_UNKNOWN: puts("Unable to identify core!"); break; case CORE_TYPE_DUMB: puts("Identified core without user interface"); break; case CORE_TYPE_MINIMIG: puts("Identified Minimig core"); break; case CORE_TYPE_PACE: puts("Identified PACE core"); break; case CORE_TYPE_MIST: puts("Identified MiST core"); break; case CORE_TYPE_8BIT: { puts("Identified 8BIT core"); // forward SD card config to core in case it uses the local // SD card implementation user_io_sd_set_config(); // check if core has a config string core_type_8bit_with_config_string = (user_io_8bit_get_string(0) != NULL); // send a reset user_io_8bit_set_status(UIO_STATUS_RESET, UIO_STATUS_RESET); // try to load config user_io_create_config_name(s); if(strlen(s) > 0) { iprintf("Loading config %s\n", s); if (FileOpen(&file, s)) { iprintf("Found config\n"); if(file.size == 1) { FileRead(&file, sector_buffer); user_io_8bit_set_status(sector_buffer[0], 0xff); } } } // release reset user_io_8bit_set_status(0, UIO_STATUS_RESET); } break; } } void user_io_analog_joystick(unsigned char joystick, char valueX, char valueY) { if(core_type == CORE_TYPE_8BIT) { EnableIO(); SPI(UIO_ASTICK); SPI(joystick); SPI(valueX); SPI(valueY); DisableIO(); } } void user_io_digital_joystick(unsigned char joystick, unsigned char map) { // iprintf("j%d: %x\n", joystick, map); // "only" 6 joysticks are supported if(joystick >= 6) return; // mist cores process joystick events for joystick 0 and 1 via the // ikbd if((core_type == CORE_TYPE_MINIMIG) || (core_type == CORE_TYPE_PACE) || ((core_type == CORE_TYPE_MIST) && (joystick >= 2)) || (core_type == CORE_TYPE_8BIT)) { // joystick 3 and 4 were introduced later EnableIO(); SPI((joystick < 2)?(UIO_JOYSTICK0 + joystick):((UIO_JOYSTICK2 + joystick - 2))); SPI(map); DisableIO(); } // atari ST handles joystick 0 and 1 through the ikbd emulated by the io controller if((core_type == CORE_TYPE_MIST) && (joystick < 2)) ikbd_joystick(joystick, map); } static char dig2ana(char min, char max) { if(min && !max) return -128; if(max && !min) return 127; return 0; } // digital joysticks also send analog signals void user_io_joystick(unsigned char joystick, unsigned char map) { user_io_digital_joystick(joystick, map); user_io_analog_joystick(joystick, dig2ana(map&JOY_LEFT, map&JOY_RIGHT), dig2ana(map&JOY_UP, map&JOY_DOWN)); } // transmit serial/rs232 data into core void user_io_serial_tx(char *chr, uint16_t cnt) { EnableIO(); SPI(UIO_SERIAL_OUT); while(cnt--) SPI(*chr++); DisableIO(); } // transmit midi data into core void user_io_midi_tx(char chr) { EnableIO(); SPI(UIO_MIDI_OUT); SPI(chr); DisableIO(); } // send ethernet mac address into FPGA void user_io_eth_send_mac(uint8_t *mac) { uint8_t i; EnableIO(); SPI(UIO_ETH_MAC); for(i=0;i<6;i++) SPI(*mac++); DisableIO(); } // set SD card info in FPGA (CSD, CID) void user_io_sd_set_config(void) { unsigned char data[33]; // get CSD and CID from SD card MMC_GetCID(data); MMC_GetCSD(data+16); // byte 32 is a generic config byte data[32] = MMC_IsSDHC()?1:0; // and forward it to the FPGA EnableIO(); SPI(UIO_SET_SDCONF); SPI_write(data, sizeof(data)); DisableIO(); hexdump(data, sizeof(data), 0); } // read 8+32 bit sd card status word from FPGA uint8_t user_io_sd_get_status(uint32_t *lba) { uint32_t s; uint8_t c; EnableIO(); SPI(UIO_GET_SDSTAT); c = SPI(0); s = SPI(0); s = (s<<8) | SPI(0); s = (s<<8) | SPI(0); s = (s<<8) | SPI(0); DisableIO(); if(lba) *lba = s; return c; } // read 32 bit ethernet status word from FPGA uint32_t user_io_eth_get_status(void) { uint32_t s; EnableIO(); SPI(UIO_ETH_STATUS); s = SPI(0); s = (s<<8) | SPI(0); s = (s<<8) | SPI(0); s = (s<<8) | SPI(0); DisableIO(); return s; } // read ethernet frame from FPGAs ethernet tx buffer void user_io_eth_receive_tx_frame(uint8_t *d, uint16_t len) { EnableIO(); SPI(UIO_ETH_FRM_IN); while(len--) *d++=SPI(0); DisableIO(); } // write ethernet frame to FPGAs rx buffer void user_io_eth_send_rx_frame(uint8_t *s, uint16_t len) { EnableIO(); SPI(UIO_ETH_FRM_OUT); SPI_write(s, len); SPI(0); // one additional byte to allow fpga to store the previous one DisableIO(); } // the physical joysticks (db9 ports at the right device side) // as well as the joystick emulation are renumbered if usb joysticks // are present in the system. The USB joystick(s) replace joystick 1 // and 0 and the physical joysticks are "shifted up". // // Since the primary joystick is in port 1 the first usb joystick // becomes joystick 1 and only the second one becomes joystick 0 // (mouse port) static uint8_t joystick_renumber(uint8_t j) { uint8_t usb_sticks = hid_get_joysticks(); // no usb sticks present: no changes are being made if(!usb_sticks) return j; if(j == 0) { // if usb joysticks are present, then physical joystick 0 (mouse port) // becomes becomes 2,3,... j = usb_sticks + 1; } else { // if one usb joystick is present, then physical joystick 1 (joystick port) // becomes physical joystick 0 (mouse) port. If more than 1 usb joystick // is present it becomes 2,3,... if(usb_sticks == 1) j = 0; else j = usb_sticks; } return j; } // 16 byte fifo for amiga key codes to limit max key rate sent into the core #define KBD_FIFO_SIZE 16 // must be power of 2 static unsigned short kbd_fifo[KBD_FIFO_SIZE]; static unsigned char kbd_fifo_r=0, kbd_fifo_w=0; static long kbd_timer = 0; static void kbd_fifo_minimig_send(unsigned short code) { EnableIO(); if(code & OSD) SPI(UIO_KBD_OSD); // code for OSD else SPI(UIO_KEYBOARD); SPI(code & 0xff); DisableIO(); kbd_timer = GetTimer(10); // next key after 10ms earliest } static void kbd_fifo_enqueue(unsigned short code) { // if fifo full just drop the value. This should never happen if(((kbd_fifo_w+1)&(KBD_FIFO_SIZE-1)) == kbd_fifo_r) return; // store in queue kbd_fifo[kbd_fifo_w] = code; kbd_fifo_w = (kbd_fifo_w + 1)&(KBD_FIFO_SIZE-1); } // send pending bytes if timer has run up static void kbd_fifo_poll() { // timer enabled and runnig? if(kbd_timer && !CheckTimer(kbd_timer)) return; kbd_timer = 0; // timer == 0 means timer is not running anymore if(kbd_fifo_w == kbd_fifo_r) return; kbd_fifo_minimig_send(kbd_fifo[kbd_fifo_r]); kbd_fifo_r = (kbd_fifo_r + 1)&(KBD_FIFO_SIZE-1); } void user_io_file_tx(fileTYPE *file) { unsigned long bytes2send = file->size; /* transmit the entire file using one transfer */ iprintf("Selected file %s with %lu bytes to send\n", file->name, bytes2send); // prepare transmission of new file EnableFpga(); SPI(UIO_FILE_TX); SPI(0xff); DisableFpga(); #if 1 while(bytes2send) { iprintf("."); unsigned short c, chunk = (bytes2send>512)?512:bytes2send; char *p; FileRead(file, sector_buffer); EnableFpga(); SPI(UIO_FILE_TX_DAT); for(p = sector_buffer, c=0;c < chunk;c++) SPI(*p++); DisableFpga(); bytes2send -= chunk; // still bytes to send? read next sector if(bytes2send) FileNextSector(file); } #else { int i, j; EnableFpga(); SPI(UIO_FILE_TX_DAT); // zx spectrum video: // 256*192 pixels = 6144 bytes // _"_ = 768 attribute bytes for(j=0;j<8;j++) for(i=0;i<32*8;i++) SPI(0xf0); for(j=0;j<8;j++) for(i=0;i<32*8;i++) SPI(0xcc); for(j=0;j<8;j++) for(i=0;i<32*8;i++) SPI(0x55); for(i=0;i<768;i++) SPI(i/3); DisableFpga(); } #endif // signal end of transmission EnableFpga(); SPI(UIO_FILE_TX); SPI(0x00); DisableFpga(); iprintf("\n"); } // 8 bit cores have a config string telling the firmware how // to treat it char *user_io_8bit_get_string(char index) { unsigned char i, lidx = 0, j = 0; static char buffer[32+1]; // max 32 bytes per config item // clear buffer buffer[0] = 0; EnableIO(); SPI(UIO_GET_STRING); i = SPI(0); // the first char returned will be 0xff if the core doesn't support // config strings. atari 800 returns 0xa4 which is the status byte if((i == 0xff) || (i == 0xa4)) { DisableIO(); return NULL; } // iprintf("String: "); while ((i != 0) && (i!=0xff) && (j complain! ErrorMessage(" This core does not support\n" " SDHC cards. Using them may\n" " lead to data corruption.\n\n" " Please use an SD card <2GB!", 0); using_sdhc = 0; } } else // SDHC request from core is always ok using_sdhc = 1; } if((c & 0x03) == 0x02) { // only write if the inserted card is not sdhc or // if the core uses sdhc if((!MMC_IsSDHC()) || (c & 0x04)) { uint8_t wr_buf[512]; // Fetch sector data from FPGA ... EnableIO(); SPI(UIO_SECTOR_WR); SPI_block_read(wr_buf); DisableIO(); // ... and write it to disk DISKLED_ON; MMC_Write(lba, wr_buf); DISKLED_OFF; } } if((c & 0x03) == 0x01) { // sector read // read sector from sd card if it is not already present in // the buffer if(buffer_lba != lba) { DISKLED_ON; if(MMC_Read(lba, buffer)) buffer_lba = lba; DISKLED_OFF; } iprintf("rd sec %d\n", lba); if(buffer_lba == lba) { // data is now stored in buffer. send it to fpga EnableIO(); SPI(UIO_SECTOR_RD); SPI_block_write(buffer); DisableIO(); // the end of this transfer acknowledges the FPGA internal // sd card emulation } // just load the next sector now, so it may be prefetched // for the next request already DISKLED_ON; if(MMC_Read(lba+1, buffer)) buffer_lba = lba+1; DISKLED_OFF; } } } // raw sector io for the atari800 core which include a full // file system driver usually implemented using a second cpu static unsigned long bit8_status = 0; unsigned long status; /* read status byte */ EnableFpga(); SPI(UIO_GET_STATUS); status = SPI(0); status = (status << 8) | SPI(0); status = (status << 8) | SPI(0); status = (status << 8) | SPI(0); DisableFpga(); if(status != bit8_status) { unsigned long sector = (status>>8)&0xffffff; char buffer[512]; bit8_status = status; // sector read testing DISKLED_ON; // sector read if(((status & 0xff) == 0xa5) || ((status & 0x3f) == 0x29)) { // extended command with 26 bits (for 32GB SDHC) if((status & 0x3f) == 0x29) sector = (status>>6)&0x3ffffff; if(MMC_Read(sector, buffer)) { // data is now stored in buffer. send it to fpga EnableFpga(); SPI(UIO_SECTOR_SND); // send sector data IO->FPGA SPI_block_write(buffer); DisableFpga(); } else bit8_debugf("rd %ld fail", sector); } // sector write if(((status & 0xff) == 0xa6) || ((status & 0x3f) == 0x2a)) { // extended command with 26 bits (for 32GB SDHC) if((status & 0x3f) == 0x2a) sector = (status>>6)&0x3ffffff; // read sector from FPGA EnableFpga(); SPI(UIO_SECTOR_RCV); // receive sector data FPGA->IO SPI_block_read(buffer); DisableFpga(); if(!MMC_Write(sector, buffer)) bit8_debugf("wr %ld fail", sector); } DISKLED_OFF; } } } char user_io_dip_switch1() { return((adc_state & 2)?1:0); } char user_io_menu_button() { return((adc_state & 4)?1:0); } char user_io_user_button() { return((adc_state & 8)?1:0); } static void send_keycode(unsigned short code) { if(core_type == CORE_TYPE_MINIMIG) { // amiga has "break" marker in msb if(code & BREAK) code = (code & 0xff) | 0x80; // send immediately if possible if(CheckTimer(kbd_timer) &&(kbd_fifo_w == kbd_fifo_r) ) kbd_fifo_minimig_send(code); else kbd_fifo_enqueue(code); } if(core_type == CORE_TYPE_MIST) { // atari has "break" marker in msb if(code & BREAK) code = (code & 0xff) | 0x80; ikbd_keyboard(code); } if(core_type == CORE_TYPE_8BIT) { // send ps2 keycodes for those cores that prefer ps2 EnableIO(); SPI(UIO_KEYBOARD); // "pause" has a complex code if((code&0xff) == 0x77) { // pause does not have a break code if(!(code & BREAK)) { // Pause key sends E11477E1F014E077 static const unsigned char c[] = { 0xe1, 0x14, 0x77, 0xe1, 0xf0, 0x14, 0xf0, 0x77, 0x00 }; const unsigned char *p = c; iprintf("PS2 KBD "); while(*p) { iprintf("%x ", *p); SPI(*p++); } iprintf("\n"); } } else { iprintf("PS2 KBD "); if(code & EXT) iprintf("e0 "); if(code & BREAK) iprintf("f0 "); iprintf("%x\n", code & 0xff); if(code & EXT) // prepend extended code flag if required SPI(0xe0); if(code & BREAK) // prepend break code if required SPI(0xf0); SPI(code & 0xff); // send code itself } DisableIO(); } } void user_io_mouse(unsigned char b, char x, char y) { // send mouse data as minimig expects it if(core_type == CORE_TYPE_MINIMIG) { EnableIO(); SPI(UIO_MOUSE); SPI(x); SPI(y); SPI(b); DisableIO(); } // 8 bit core expects ps2 like data if(core_type == CORE_TYPE_8BIT) { // collect movement info and send at predefined rate EnableIO(); SPI(UIO_MOUSE); // PS2 format: // XOvfl, YOvfl, dy8, dx8, 1, mbtn, rbtn, lbtn // dx[7:0] // dy[7:0] iprintf("PS2 MOUSE: %x %d %d\n", ((y>0)?0x20:0) | ((x<0)?0x10:0) | 0x08 | (b&3), x, -y); SPI(((y>0)?0x20:0) | ((x<0)?0x10:0) | 0x08 | (b&3)); SPI(x); SPI(-y); DisableIO(); } // send mouse data as mist expects it if(core_type == CORE_TYPE_MIST) ikbd_mouse(b, x, y); } // check if this is a key that's supposed to be suppressed // when emulation is active static unsigned char is_emu_key(unsigned char c) { static const unsigned char m[] = { JOY_RIGHT, JOY_LEFT, JOY_DOWN, JOY_UP }; if(emu_mode == EMU_NONE) return 0; // direction keys R/L/D/U if(c >= 0x4f && c <= 0x52) return m[c-0x4f]; return 0; } /* usb modifer bits: 0 1 2 3 4 5 6 7 LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI */ #define EMU_BTN1 0 // left control #define EMU_BTN2 1 // left shift #define EMU_BTN3 2 // left alt #define EMU_BTN4 3 // left gui (usually windows key) unsigned short keycode(unsigned char in) { if(core_type == CORE_TYPE_MINIMIG) return usb2ami[in]; // atari st and the 8 bit core (currently only used for atari 800) // use the same key codes if(core_type == CORE_TYPE_MIST) return usb2atari[in]; if(core_type == CORE_TYPE_8BIT) return usb2ps2[in]; return MISS; } void check_reset(unsigned char modifiers) { if(core_type==CORE_TYPE_MINIMIG) { if(modifiers==0x45) // ctrl - alt - alt OsdReset(RESET_NORMAL); } } unsigned short modifier_keycode(unsigned char index) { /* usb modifer bits: 0 1 2 3 4 5 6 7 LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI */ if(core_type == CORE_TYPE_MINIMIG) { static const unsigned short amiga_modifier[] = { 0x63, 0x60, 0x64, 0x66, 0x63, 0x61, 0x65, 0x67 }; return amiga_modifier[index]; } if(core_type == CORE_TYPE_MIST) { static const unsigned short atari_modifier[] = { 0x1d, 0x2a, 0x38, MISS, 0x1d, 0x36, 0x38, MISS }; return atari_modifier[index]; } if(core_type == CORE_TYPE_8BIT) { static const unsigned short ps2_modifier[] = { 0x14, 0x12, 0x11, EXT|0x1f, EXT|0x14, 0x59, EXT|0x11, EXT|0x27 }; return ps2_modifier[index]; } return MISS; } // set by OSD code to suppress forwarding of those keys to the core which // may be in use by an active OSD static char osd_eats_keys = false; void user_io_osd_key_enable(char on) { osd_eats_keys = on; } static char key_used_by_osd(unsigned short s) { // this key is only used in OSD and has no keycode if((s & OSD_LOC) && !(s & 0xff)) return true; // no keys are suppressed if the OSD is inactive if(!osd_eats_keys) return false; // in atari mode eat all keys if the OSD is online, // else none as it's up to the core to forward keys // to the OSD return((core_type == CORE_TYPE_MIST) || (core_type == CORE_TYPE_8BIT)); } void user_io_kbd(unsigned char m, unsigned char *k) { if((core_type == CORE_TYPE_MINIMIG) || (core_type == CORE_TYPE_MIST) || (core_type == CORE_TYPE_8BIT)) { static unsigned char modifier = 0, pressed[6] = { 0,0,0,0,0,0 }; int i, j; // modifier keys are used as buttons in emu mode if(emu_mode != EMU_NONE) { char last_btn = emu_state & (JOY_BTN1 | JOY_BTN2 | JOY_BTN3 | JOY_BTN4); if(m & (1<