📄 skyeye_mach_s3c44b0x.c
字号:
/* skyeye_mach_s3c44b0x.c - SAMSUNG's S3C44B0X simulation for skyeye Copyright (C) 2003 - 2007 Skyeye Develop Group for help please send mail to <skyeye-developer@lists.gro.clinux.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* * 07/19/2003 original implementation by Walimis <wlm@student.dlut.edu.cn> * 03/04/2007 rewritten by Anthony Lee <don.anthony.lee+program@gmail.com> *//* * COMPLETED: Interrupt, UART, PWM Timers, Watchdog Timer, LCD, NET, RTC, DMA, IIS * UNIMPLEMENTED: I/O Ports, etc. * * NOTE: * LCD: see "device/lcd/dev_lcd_s3c44b0x.c[h]" * SOUND: see "device/sound/dev_sound_s3c44b0x.c" * NET(RTL8019AS 8/16 bits): see "device/net/dev_net_rtl8019.c[h]" */#include "armdefs.h"#include "armemu.h"#include "s3c44b0.h"#include "skyeye_uart.h"#include "portable/gettimeofday.h"#define S3C44B0X_DEBUG 0#define PRINT(x...) printf("[S3C44B0X]: " x)#if S3C44B0X_DEBUG#define DEBUG(x...) printf("[S3C44B0X]: " x)#else#define DEBUG(x...) (void)0#endif/* * CYCLE_TIMES_PER_SECOND: * It's near 40000 times on my machine, * you can change the value to fit your machine. */#define CYCLE_TIMES_PER_SECOND (40000)#define MCLK (64) /* MHz */#define TIMER_COUNT_DOWN_PER_SECOND ((1000000 * MCLK) >> 1) /* prescale=1, divider=1/2 */#define TIMER_COUNT_DOWN_PER_CYCLE (TIMER_COUNT_DOWN_PER_SECOND / CYCLE_TIMES_PER_SECOND)#define BCD_TO_BIN(a) (((a) >> 4) * 10 + ((a) & 0xf))#define BIN_TO_BCD(a) ((((a) / 10) << 4) | ((a) % 10))#define HALFWORD_SWAP(x) (((x) >> 8) | ((x) << 8))#define WORD_SWAP(x) ((HALFWORD_SWAP((x) & 0xffff) << 16) | HALFWORD_SWAP(((x) >> 16) & 0xffff))struct s3c44b0x_uart_fifo{ unsigned char rx[16]; unsigned char tx[16]; ARMword txcnt;};typedef ARMword (s3c44b0x_dma_t)[8];#define DMA_CON(dma) dma[0]#define DMA_ISRC(dma) dma[1]#define DMA_IDES(dma) dma[2]#define DMA_ICNT(dma) dma[3]#define DMA_CSRC(dma) dma[4]#define DMA_CDES(dma) dma[5]#define DMA_CCNT(dma) dma[6]#define DMA_FLY(dma) dma[7]extern ARMword mem_read_byte(ARMul_State*, ARMword);extern ARMword mem_read_halfword(ARMul_State*, ARMword);extern ARMword mem_read_word(ARMul_State*, ARMword);extern void mem_write_byte(ARMul_State*, ARMword, ARMword);extern void mem_write_halfword(ARMul_State*, ARMword, ARMword);extern void mem_write_word(ARMul_State*, ARMword, ARMword);extern ARMword io_read_byte(ARMul_State*, ARMword);extern ARMword io_read_halfword(ARMul_State*, ARMword);extern ARMword io_read_word(ARMul_State*, ARMword);extern void io_write_byte(ARMul_State*, ARMword, ARMword);extern void io_write_halfword(ARMul_State*, ARMword, ARMword);extern void io_write_word(ARMul_State*, ARMword, ARMword);typedef ARMword (*s3c44b0x_dma_read_func)(ARMul_State*, ARMword);typedef void (*s3c44b0x_dma_write_func)(ARMul_State*, ARMword, ARMword);static s3c44b0x_dma_read_func dma_read_funcs[12] = { /* ZDMA */ mem_read_byte, mem_read_halfword, mem_read_word, /* BDMA */ mem_read_byte, io_read_byte, io_read_byte, mem_read_halfword, io_read_halfword, io_read_halfword, mem_read_word, io_read_word, io_read_word,};static s3c44b0x_dma_write_func dma_write_funcs[12] = { /* ZDMA */ mem_write_byte, mem_write_halfword, mem_write_word, /* BDMA */ io_write_byte, mem_write_byte, io_write_byte, io_write_halfword, mem_write_halfword, io_write_halfword, io_write_word, mem_write_word, io_write_word,};/* S3C44B0X Internal IO Registers */struct s3c44b0x_io_t{ /* CPU Wrapper Registers : FIXME */ ARMword syscfg; ARMword ncachbe0; ARMword ncachbe1; ARMword sbuscon; /* Memory Controller Registers : FIXME */ ARMword bwscon; /* Interrupt Controller Registers */ ARMword intcon; ARMword intpnd; ARMword intmod; ARMword intmsk; ARMword i_pslv; ARMword i_pmst; ARMword i_cslv; ARMword i_cmst; /* UART Registers */ ARMword ulcon0; ARMword ulcon1; ARMword ucon0; ARMword ucon1; ARMword ufcon0; ARMword ufcon1; ARMword umcon0; ARMword umcon1; ARMword utrstat0; ARMword utrstat1; ARMword uerstat0; ARMword uerstat1; ARMword ufstat0; ARMword ufstat1; ARMword umstat0; ARMword umstat1; ARMword urxh0; ARMword urxh1; ARMword ubrdiv0; ARMword ubrdiv1; struct s3c44b0x_uart_fifo ufifo0; struct s3c44b0x_uart_fifo ufifo1; /* PWM Timers Registers */ ARMword tcfg0; ARMword tcfg1; ARMword tcnt_scaler[7]; ARMword tprescaler[7]; ARMword tdivider[7]; ARMword tcon; ARMword tcntb[6]; ARMword tcmpb[5]; ARMword tcnt[6]; ARMword tcmp[5]; /* Watchdog Timer Registers */ ARMword wtcon; ARMword wtdat; ARMword wtcnt; /* RTC Registers */ ARMword rtccon; ARMword rtcalm; ARMword rtcrst; ARMword ticint; ARMword tick_count; struct tm rtc_alarm; long int rtc_offset; /* DMA Registers */ s3c44b0x_dma_t dma[4]; /* IIS Registers */ ARMword iiscon; ARMword iismod; ARMword iispsr; ARMword iisfifcon; ARMhword iisfifo_rx[8]; ARMhword iisfifo_tx[8]; ARMword iisfifo_txcnt;};static struct s3c44b0x_io_t s3c44b0x_io;ARMhword *s3c44b0x_iisfifo_tx = NULL;#define io s3c44b0x_iostatic int s3c44b0x_dma_is_valid(int index);static void s3c44b0x_dma_proccess(ARMul_State *state, int index);static void s3c44b0x_io_reset(ARMul_State *state){ memset(&io, 0, sizeof(io)); /* CPU Wrapper */ io.syscfg = 0x1; io.sbuscon = 0x80001b1b; /* Memory Controller */ io.bwscon = (state->bigendSig ? 0x1 : 0x0); /* Interrupt */ io.intcon = 0x7; io.intmsk = 0x7ffffff; io.i_pslv = 0x1b1b1b1b; io.i_pmst = 0x1f1b; io.i_cslv = 0x1b1b1b1b; io.i_cmst = 0x1b; /* UART */ io.utrstat0 = io.utrstat1 = 0x6; /* Watchdog Timer */ io.wtcon = 0x8020; /* here we disabled watchdog */ io.wtdat = 0x8000; io.wtcnt = 0x8000; io.tdivider[6] = 4; /* RTC */ io.rtc_alarm.tm_mday = 1; /* IIS */ io.iiscon = 0x100; s3c44b0x_iisfifo_tx = &io.iisfifo_tx[0];}/* Interrupt Routine */static void s3c44b0x_update_int(ARMul_State *state){ ARMword requests = (io.intmsk & (0x1 << INT_GLOBAL)) ? 0x0 : (io.intpnd & ~io.intmsk); ARMword vector, irq; state->NfiqSig = ((io.intcon & 0x1) == 0 ? ((requests & io.intmod) ? LOW : HIGH) : HIGH); state->NirqSig = ((io.intcon & 0x2) == 0 ? ((requests & ~io.intmod) ? LOW : HIGH) : HIGH);}static void s3c44b0x_update_intr(struct machine_config *mach){ /* leave me alone, do nothing ... */}static int s3c44b0x_pending_intr(unsigned int irq){ /* Here we "return 1" so that the device won't do something for it */ if (!((io.intcon & 0x2) == 0x0 || (io.intcon & 0x5) == 0x4)) return 1; if (io.intmsk & (0x1 << INT_GLOBAL)) return 1; return ((io.intpnd & (0x1 << irq)) == 0 ? 0 : 1);}static void s3c44b0x_set_interrupt(unsigned int irq){ if ((io.intcon & 0x2) == 0x0 || (io.intcon & 0x5) == 0x4) { /* IRQ or FIQ enabled */ io.intpnd |= (0x1 << irq); }}static void s3c44b0x_interrupt_read(ARMword addr, ARMword *data){ int i; switch (addr) { case INTCON: *data = io.intcon; break; case INTPND: *data = ((io.intmsk & (0x1 << INT_GLOBAL)) ? 0x1 : io.intpnd); break; case INTMOD: *data = io.intmod; break; case INTMSK: *data = io.intmsk; break; case I_PSLV: *data = io.i_pslv; break; case I_PMST: *data = io.i_pmst; break; case I_CSLV: *data = io.i_cslv; break; case I_CMST: *data = io.i_cmst; break; case I_ISPR: *data = 0; if (io.intmsk & (0x1 << INT_GLOBAL)) break; if ((io.intcon & 0x2) != 0x0) break; for (i = 0; i < 26; i++) { /* find which interrupt is pending */ if (((io.intpnd & ~io.intmsk) & (0x1 << i)) & ~io.intmod) { *data = (0x1 << i); break; } } break; case F_ISPR: *data = 0; if (io.intmsk & (0x1 << INT_GLOBAL)) break; if ((io.intcon & 0x5) != 0x4) break; for (i = 0; i < 26; i++) { /* find which interrupt is pending */ if (((io.intpnd & ~io.intmsk) & (0x1 << i)) & io.intmod) { *data = (0x1 << i); break; } } break; default: break; } DEBUG("%s(addr:0x%x, data:0x%x)\n", __FUNCTION__, addr, *data);}static void s3c44b0x_interrupt_write(ARMul_State *state, ARMword addr, ARMword data){ DEBUG("%s(addr:0x%x, data:0x%x)\n", __FUNCTION__, addr, data); switch (addr) { case INTCON: io.intcon = data; break; case INTMOD: io.intmod = data; break; case INTMSK: io.intmsk = data; break; case I_PSLV: io.i_pslv = data; break; case I_PMST: io.i_pmst = data; break; case I_ISPC: if ((io.intcon & 0x2) != 0x0 || ((data & 0x3ffffff) & ~io.intmod) == 0) break; io.intpnd &= (~data & 0x3ffffff); break; case F_ISPC: if ((io.intcon & 0x5) != 0x4 || ((data & 0x3ffffff) & io.intmod) == 0) break; io.intpnd &= (~data & 0x3ffffff); break; default: break; }}/* UART Routine */static void s3c44b0x_uart_do_cycle(ARMul_State *state){ int read_uart0 = 1; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; do { ARMword *pUfstat = (read_uart0 ? &io.ufstat0 : &io.ufstat1); ARMword *pUtrstat = (read_uart0 ? &io.utrstat0 : &io.utrstat1); ARMword *pUcon = (read_uart0 ? &io.ucon0 : &io.ucon1); ARMword *pUfcon = (read_uart0 ? &io.ufcon0 : &io.ufcon1); ARMword *pUrxh = (read_uart0 ? &io.urxh0 : &io.urxh1); ARMword bdma_mask = (read_uart0 ? 0x2 : 0x3); if ((*pUcon & 0x3) == bdma_mask || (*pUcon & 0xc) == (bdma_mask << 2)) { /* BDMA request */ ARMword utxhb = (read_uart0 ? UTXH0 : UTXH1) + state->bigendSig * 3; ARMword urxhb = (read_uart0 ? URXH0 : URXH1) + state->bigendSig * 3; int index = (read_uart0 ? 2 : 3); int rx_empty = ((*pUfcon & 0x1) ? ((*pUfstat & 0xf) == 0) : ((*pUtrstat & 0x1) == 0)); int tx_ready = ((*pUfcon & 0x1) ? ((*pUfstat & 0x200) == 0) : 1); ARMword mask = 0; if ((*pUcon & 0x3) == 0x0) rx_empty = 1; if ((*pUcon & 0xc) == 0x0) tx_ready = 0; do { if (s3c44b0x_dma_is_valid(index) != 1) break; if (((DMA_CCNT(io.dma[index]) >> 30) & 0x3) != 0x2) break; if ((DMA_CDES(io.dma[index]) & 0xfffffff) == utxhb && tx_ready) mask |= (bdma_mask << 2); if ((DMA_CSRC(io.dma[index]) & 0xfffffff) == urxhb && !rx_empty) mask |= bdma_mask; if ((*pUcon & mask) != 0) s3c44b0x_dma_proccess(state, index); } while (0); } if (*pUfcon & 0x1) { /* FIFO mode */ struct s3c44b0x_uart_fifo *pUfifo = (read_uart0 ? &io.ufifo0 : &io.ufifo1); int count, tmp_count; if ((*pUfstat & 0x100) == 0 && (*pUcon & 0x3) != 0x0) { /* FIFO not full */ tmp_count = count = (*pUfstat & 0xf); count += skyeye_uart_read(read_uart0 ? 0 : 1, &pUfifo->rx[count], 16 - count, &tv, NULL); if (count > tmp_count) { *pUfstat &= ~0xf; *pUfstat |= (count == 16 ? 0x10f : count); } } while ((count = ((*pUfstat & 0xf0) >> 4)) > 0 && (*pUcon & 0xc) != 0x0) { /* handling TX FIFO */ if (pUfifo->txcnt > 0) { pUfifo->txcnt -= 1; break; } if (*pUfstat & 0x200) count++; tmp_count = skyeye_uart_write(read_uart0 ? 0 : 1, &pUfifo->tx[0], count, NULL); if (tmp_count <= 0) break; count -= tmp_count; *pUfstat &= ~0x2f0; if (count > 0) { *pUfstat |= (count << 4); memmove(&pUfifo->tx[0], &pUfifo->tx[tmp_count], (size_t)count); } else { pUfifo->txcnt = 64; } if ((*pUcon & 0xc) == 0x4) { /* Transmit Mode: Interrupt request or polling mode */ s3c44b0x_set_interrupt(read_uart0 ? INT_UTXD0 : INT_UTXD1); } break; } if ((*pUfstat & 0xf) == 0) continue; *pUrxh = (ARMword)pUfifo->rx[0]; } else { /* non FIFO mode */ unsigned char buf; if ((*pUcon & 0x3) == 0x0) continue; if (*pUtrstat & 0x1) continue; if (skyeye_uart_read(read_uart0 ? 0 : 1, &buf, 1, &tv, NULL) <= 0) continue; *pUrxh = (ARMword)buf; *pUtrstat |= 0x1; } if ((*pUcon & 0x3) == 0x1) s3c44b0x_set_interrupt(read_uart0 ? INT_URXD0 : INT_URXD1); } while((read_uart0--) && skyeye_config.uart.count > 1);}static void s3c44b0x_uart_read(ARMword addr, ARMword *data){ switch (addr) { case ULCON0: *data = io.ulcon0; break; case ULCON1: *data = io.ulcon1; break; case UCON0: *data = io.ucon0; break; case UCON1: *data = io.ucon1; break; case UFCON0: *data = io.ufcon0; break; case UFCON1: *data = io.ufcon1; break; case UMCON0: *data = io.umcon0; break; case UMCON1: *data = io.umcon1; break; case UTRSTAT0: *data = io.utrstat0; break; case UTRSTAT1: *data = io.utrstat1; break; case UERSTAT0: *data = io.uerstat0; break; case UERSTAT1: *data = io.uerstat1; break; case UFSTAT0: *data = io.ufstat0; break; case UFSTAT1: *data = io.ufstat1; break; case UMSTAT0: *data = io.umstat0; break; case UMSTAT1: *data = io.umstat1; break; case URXH0: case URXH1: { ARMword *pUfstat = (addr == URXH0 ? &io.ufstat0 : &io.ufstat1); ARMword *pUtrstat = (addr == URXH0 ? &io.utrstat0 : &io.utrstat1); ARMword *pUfcon = (addr == URXH0 ? &io.ufcon0 : &io.ufcon1); ARMword *pUrxh = (addr == URXH0 ? &io.urxh0 : &io.urxh1); *data = (*pUrxh); if (*pUfcon & 0x1) { /* FIFO mode */ ARMword *pUcon = (addr == URXH0 ? &io.ucon0 : &io.ucon1); struct s3c44b0x_uart_fifo *pUfifo = (addr == URXH0 ? &io.ufifo0 : &io.ufifo1); int count = (*pUfstat & 0xf); if (count == 0) break; if (*pUfstat & 0x100) count++; *pUfstat &= ~0x10f; if (count == 1) break; *pUfstat |= (--count); memmove(&pUfifo->rx[0], &pUfifo->rx[1], (size_t)count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -