📄 skyeye_mach_s3c3410x.c
字号:
/* skyeye_mach_s3c3410x.c - SAMSUNG's S3C3410X simulation for skyeye Copyright (C) 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 *//* * 03/04/2007 Written by Anthony Lee *//* * COMPLETED: Interrupt, WatchDog, Timer, UART, DMA * UNIMPLEMENTED: I/O Port, etc. */#include "armdefs.h"#include "armemu.h"#include "s3c3410x.h"#include "skyeye_uart.h"#define S3C3410X_DEBUG 0#define PRINT(x...) printf("[S3C3410X]: " x)#if S3C3410X_DEBUG#define DEBUG(x...) printf("[S3C3410X]: " 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 (40) /* MHz */#define TIMER_COUNT_UP_PER_SECOND (1000000 * MCLK) /* prescale=1, divider=1 */#define TIMER_COUNT_UP_PER_CYCLE (TIMER_COUNT_UP_PER_SECOND / CYCLE_TIMES_PER_SECOND)struct s3c3410x_timer_t { ARMword tdat; ARMword tpre; ARMword tcon; ARMword tcnt; ARMword tcnt_scaler;};struct s3c3410x_dma_t { ARMword con; ARMword src; ARMword dst; ARMword cnt;};/* S3C3410X Internal IO Registers */struct s3c3410x_io_t{ /* System Registers */ ARMword syscfg; ARMword syscon; /* Interrupt Controller Registers */ ARMword intmod; ARMword intpnd; ARMword intmsk; ARMword intpri[8]; /* Timer Registers */ ARMword btcon; ARMword btcnt; ARMword btcnt_scaler; struct s3c3410x_timer_t timer[5]; ARMword tfcon; ARMword tfstat; uint64_t tf4; ARMword tf4_repeat[2]; /* UART Registers */ ARMword ulcon; ARMword ucon; ARMword ustat; ARMword ufcon; ARMword ufstat; ARMword urxh; ARMword ubrdiv; /* DMA Registers */ struct s3c3410x_dma_t dma[2];};static struct s3c3410x_io_t s3c3410x_io;#define io s3c3410x_ioextern 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);static int s3c3410x_dma_is_valid(int index);static void s3c3410x_dma_proccess(ARMul_State *state, int index);static void s3c3410x_io_reset(ARMul_State *state){ int i; memset(&io, 0, sizeof(io)); /* System */ io.syscfg = 0xfff1; /* Interrupt */ io.intpri[0] = 0x03020100; io.intpri[1] = 0x07060504; io.intpri[2] = 0x0b0a0908; io.intpri[3] = 0x0f0e0d0c; io.intpri[4] = 0x13121110; io.intpri[5] = 0x17161514; io.intpri[6] = 0x1b1a1918; io.intpri[7] = 0x1f1e1d1c; /* Timer */ for (i = 0; i < 5; i++) io.timer[i].tpre = 0xff; for (i = 0; i < 3; i++) io.timer[i].tdat = 0xffff; for (i = 3; i < 5; i++) io.timer[i].tdat = 0xff; /* UART */ io.ustat = 0xc0;}/* Interrupt Routine */static void s3c3410x_update_int(ARMul_State *state){ ARMword requests = (io.syscon & 0x40) ? (io.intpnd & io.intmsk) : 0x0; state->NfiqSig = (requests & io.intmod) ? LOW : HIGH; state->NirqSig = (requests & ~io.intmod) ? LOW : HIGH;}static void s3c3410x_set_interrupt(unsigned int irq){ io.intpnd |= (0x1 << irq);}static void s3c3410x_interrupt_read(ARMword addr, ARMword *data){ switch (addr) { case INTMOD: *data = io.intmod; break; case INTPND: *data = io.intpnd; break; case INTMSK: *data = io.intmsk; break; case INTPRI0: case INTPRI1: case INTPRI2: case INTPRI3: case INTPRI4: case INTPRI5: case INTPRI6: case INTPRI7: *data = io.intpri[(addr - INTPRI0) / 0x4]; break; default: break; } DEBUG("%s(addr:0x%x, data:0x%x)\n", __FUNCTION__, addr, *data);}static void s3c3410x_interrupt_write(ARMul_State *state, ARMword addr, ARMword data){ DEBUG("%s(addr:0x%x, data:0x%x)\n", __FUNCTION__, addr, data); switch (addr) { case INTMOD: io.intmod = data; break; case INTPND: io.intpnd &= data; break; case INTMSK: io.intmsk = data; break; case INTPRI0: case INTPRI1: case INTPRI2: case INTPRI3: case INTPRI4: case INTPRI5: case INTPRI6: case INTPRI7: io.intpri[(addr - INTPRI0) / 0x4] = data; break; default: break; }}/* Timer Routine */static void s3c3410x_timer_do_cycle(ARMul_State *state){ int i, k; ARMword tdat, count, empty_count; ARMword cnt_up, cnt_divider, cnt_clock_divider = 1;#if 0 switch ((io.syscon >> 3) & 0x7) { case 0: cnt_clock_divider = 16; break; case 1: cnt_clock_divider = 8; break; case 2: cnt_clock_divider = 2; break; case 4: cnt_clock_divider = 1024; break; default: break; }#endif for (i = 0; i < 5; i++) { if ((io.timer[i].tcon & 0x80) == 0) continue; if (i < 4 || (io.tfcon & 0x1) == 0) { tdat = io.timer[i].tdat; } else { if ((count = (io.tfstat & 0x7)) == 0) break; if (io.timer[4].tcnt == (tdat = (io.tf4 & 0xff))) { if (io.tf4_repeat[0] == 0) { io.tf4_repeat[0] = io.tf4_repeat[1]; if ((empty_count = ((io.tfcon >> 2) & 0x3)) > 0) { if (empty_count == 3) empty_count = 4; if (io.tfstat & 0x8) count++; io.tfstat = count - min(empty_count, count); io.tf4 >>= (empty_count << 3); } s3c3410x_set_interrupt(INT_TF); } else { io.tf4_repeat[0] -= 1; } } } cnt_divider = cnt_clock_divider * (io.timer[i].tpre + 1) << (i < 3 ? 0 : (1 << (4 - (io.timer[i].tcon & 0x3)))); cnt_up = TIMER_COUNT_UP_PER_CYCLE / cnt_divider; if (cnt_up == 0) { if (io.timer[i].tcnt_scaler == 0) { io.timer[i].tcnt_scaler = cnt_divider / TIMER_COUNT_UP_PER_CYCLE; continue; } else if ((io.timer[i].tcnt_scaler -= 1) != 0) { continue; } cnt_up = 1; } switch ((io.timer[i].tcon >> 3) & 0x7) { case 0: /* Interval Mode */ if (io.timer[i].tcnt == tdat) { s3c3410x_set_interrupt(INT_TMC0 + i * 2); io.timer[i].tcnt = 0; break; } if (io.timer[i].tcnt > tdat) break; io.timer[i].tcnt += min(tdat - io.timer[i].tcnt, cnt_up); break; case 1: /* Match & overflow mode (Timer0/1/2), PWM mode (Timer3/4) */ if (io.timer[i].tcnt == tdat) { s3c3410x_set_interrupt(INT_TMC0 + i * 2); } if (io.timer[i].tcnt == (i < 3 ? 0xffff : 0xff)) { s3c3410x_set_interrupt(INT_TOF0 + i * 2); io.timer[i].tcnt = 0; break; } io.timer[i].tcnt += min((io.timer[i].tcnt < tdat ? tdat : (i < 3 ? 0xffff : 0xff)) - io.timer[i].tcnt, cnt_up); break; case 2: /* Match & DMA mode */ if (!(i == 1 || i == 3)) break; for (k = 0; k < 2; k++) { if (s3c3410x_dma_is_valid(k) != 1) continue; if (((io.dma[k].con >> 2) & 0x3) != 0x3) continue; if (i == 1 && io.dma[k].dst == TDAT1) break; if (i == 3 && io.dma[k].dst == TDAT3) break; } if (k == 2) break; if (io.timer[i].tcnt == tdat) { s3c3410x_set_interrupt(INT_TMC0 + i * 2); io.timer[i].tcnt = 0; s3c3410x_dma_proccess(state, k); break; } if (io.timer[i].tcnt > tdat) break; io.timer[i].tcnt += min(tdat - io.timer[i].tcnt, cnt_up); break; default: /* Other mode unimplemented yet */ break; } } /* Basic Timer and WatchDog */ cnt_divider = 1 << (13 - ((io.btcon >> 2) & 0x3)); cnt_up = TIMER_COUNT_UP_PER_CYCLE / cnt_divider; if (cnt_up == 0) { if (io.btcnt_scaler == 0) { io.btcnt_scaler = cnt_divider / TIMER_COUNT_UP_PER_CYCLE; goto next; } else if ((io.btcnt_scaler -= 1) != 0) { goto next; } cnt_up = 1; } if (io.btcnt == 0xff) { io.btcnt = 0; s3c3410x_set_interrupt(INT_BT); } else { io.btcnt += min(0xff - io.btcnt, cnt_up); } if (io.btcon & 0x10000) { ARMword wdt = (io.btcon >> 8) & 0xff; if (wdt == 0xff) { /* asserts reset signal */ state->NresetSig = LOW; PRINT("****************** WATCHDOG RESET ******************\n"); } else { io.btcon = (io.btcon & ~0xff00) | ((wdt + min(0xff - wdt, cnt_up)) << 8); } }next: return;}static void s3c3410x_timer_read(ARMword offset, ARMword *data, int index){ switch (offset) { case 0: /* TDAT */ *data = io.timer[index].tdat; break; case 2: /* TPRE */ *data = io.timer[index].tpre; break; case 3: /* TCON */ *data = io.timer[index].tcon; break; case 6: /* TCNT */ *data = io.timer[index].tcnt; break; case 0x8: /* TFW4 */ if (index != 4) break; if ((io.tfcon & 0x1) == 0 || io.tfstat == 0) break; *data = io.tf4 & 0xffffffff; io.tf4 >>= 32; io.tfstat = (io.tfstat < 7 ? (io.tfstat - min(io.tfstat, 4)) : (io.tfstat & ~0x8)); break; case 0xa: /* TFHW4 */ if (index != 4) break; if ((io.tfcon & 0x1) == 0 || io.tfstat == 0) break; *data = io.tf4 & 0xffff; io.tf4 >>= 16; io.tfstat = (io.tfstat < 7 ? (io.tfstat - min(io.tfstat, 2)) : (io.tfstat & ~0x8)); break; case 0xb: /* TFB4 */ if (index != 4) break; if ((io.tfcon & 0x1) == 0 || io.tfstat == 0) break; *data = io.tf4 & 0xff; io.tf4 >>= 8; io.tfstat = (io.tfstat < 7 ? (io.tfstat - 1) : (io.tfstat & ~0x8)); break; case 0xe: /* TFSTAT */ if (index == 4) *data = io.tfstat; break; case 0xf: /* TFCON */ if (index == 4) *data = io.tfcon; break; default: break; } DEBUG("%s(Timer%d, offset:0x%x, data:0x%x)\n", __FUNCTION__, index, offset, *data);}static void s3c3410x_timer_write(ARMul_State *state, ARMword offset, ARMword data, int index){ DEBUG("%s(Timer%d, offset:0x%x, data:0x%x)\n", __FUNCTION__, index, offset, data); switch (offset) { case 0: /* TDAT */ io.timer[index].tdat = min(data, (index < 3 ? 0xffff : 0xff)); break; case 2: /* TPRE */ io.timer[index].tpre = min(data, 0xff); break; case 3: /* TCON */ io.timer[index].tcon = min((data & ~0x40), 0xff); if (data & 0x40) io.timer[index].tcnt = 0; break; case 0x8: /* TFW4 */ if (index != 4) break; if ((io.tfcon & 0x1) == 0 || io.tfstat > 7) break; io.tf4 &= ~(((uint64_t)0xffffffff) << (io.tfstat << 3)); io.tf4 |= (((uint64_t)data) << (io.tfstat << 3)); io.tfstat += (io.tfstat < 4 ? 4 : 8); break; case 0xa: /* TFHW4 */ if (index != 4) break; if ((io.tfcon & 0x1) == 0 || io.tfstat > 7) break; io.tf4 &= ~(((uint64_t)0xffff) << (io.tfstat << 3)); io.tf4 |= (((uint64_t)min(data, 0xffff)) << (io.tfstat << 3)); io.tfstat += (io.tfstat < 6 ? 2 : 8); break; case 0xb: /* TFB4 */ if (index != 4) break; if ((io.tfcon & 0x1) == 0 || io.tfstat > 7) break; io.tf4 &= ~(((uint64_t)0xff) << (io.tfstat << 3));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -