From 32f507ce5f66dd9c89a45854688f46bde33c5e3d Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 10 Nov 2010 09:20:50 +0100 Subject: Initial import of nios2sim (http://nios2sim.googlecode.com/svn/trunk/ r16) --- timer.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 timer.c (limited to 'timer.c') diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..b468f9b --- /dev/null +++ b/timer.c @@ -0,0 +1,215 @@ +/* + Nios-sim - one simple NIOSII simulator only for personal interest and fun. + Copyright (C) 2010 chysun2000@gmail.com + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include + +#include "public.h" +#include "timer.h" +#include "niosii.h" + + +static struct timer_hw hw; +static uint32_t valid_mask[TIMER_REG_CNT] = { + 0x3,0xF,0xFFFF,0xFFFF,0xFFFF,0xFFFF +}; + +static uint32_t only_read_mask[TIMER_REG_CNT] = { + 0x2,0,0,0,0,0 +}; + +static void update_period_reg(void); +static void timer_init(struct io_device * self) +{ + int32_t i = 0; + + self->priv_data = &hw; + + for (i=0;i= TIMER_BASE_ADDR) && (address < (TIMER_BASE_ADDR + TIMER_REG_CNT * 4))){ + ret_val = ADDR_IS_DEV; + } + + return ret_val; +} +static void copy_snapshot(void); +static uint32_t timer_read(struct io_device * self, uint32_t addr, uint32_t data_len) +{ + uint32_t ret_val = 0; + uint32_t index = 0; + + index = (addr - TIMER_BASE_ADDR) / 4; + if (index >= 0 && index < TIMER_REG_CNT){ + if (index == TIM_REG_SNAPL || index == TIM_REG_SNAPH){ + copy_snapshot(); + } + ret_val = hw.io_regs[index].value & hw.io_regs[index].valid_mask; + ret_val = io_read_data(ret_val, data_len); + } + return ret_val; +} + +static void timer_write(struct io_device * self, uint32_t addr, uint32_t data, uint32_t data_len) +{ + uint32_t index = 0; + uint32_t temp = 0; + uint32_t only_read_mask = 0; + uint32_t valid_mask = 0; + + index = (addr - TIMER_BASE_ADDR) / 4; + + if (index >= 0 && index < TIMER_REG_CNT){ + temp = hw.io_regs[index].value; + valid_mask = hw.io_regs[index].valid_mask; + only_read_mask = hw.io_regs[index].only_read_mask; + hw.io_regs[index].value = io_write_data_mask(temp, data, data_len, valid_mask, only_read_mask); + + + if (index == TIM_REG_PERIODL){ + hw.set_period = hw.set_period &0xFFFF0000; + hw.set_period = hw.set_period | (data & 0xFFFF); + hw.curr_count = hw.set_period; + update_period_reg(); + } + else if (index == TIM_REG_PERIODH){ + hw.set_period = hw.set_period & 0xFFFF; + hw.set_period = hw.set_period | ((data & 0xFFFF) <<16); + hw.curr_count = hw.set_period; + update_period_reg(); + } + else if (index == TIM_REG_STATUS){ + if ((hw.io_regs[index].value & STATUS_TO_MASK) == 0){ + clean_ipending(self->irq_enable_mask); + } + } + } +} + +static int32_t timer_has_irq(struct io_device * self) +{ + int32_t ret_val = DEV_NO_IRQ; + uint32_t ctrl_reg_val = 0; + uint32_t status_reg_val = 0; + + ctrl_reg_val = hw.io_regs[TIM_REG_CTRL].value & hw.io_regs[TIM_REG_CTRL].valid_mask; + status_reg_val = hw.io_regs[TIM_REG_STATUS].value & hw.io_regs[TIM_REG_STATUS].valid_mask; + + if ((ctrl_reg_val & CTRL_ITO_MASK) == CTRL_ITO_MASK){ + if ((status_reg_val & STATUS_TO_MASK) == STATUS_TO_MASK){ + ret_val = DEV_HAS_IRQ; + } + } + return ret_val; +} + +static void copy_snapshot(void) +{ + hw.io_regs[TIM_REG_SNAPL].value = hw.io_regs[TIM_REG_PERIODL].value; + hw.io_regs[TIM_REG_SNAPH].value = hw.io_regs[TIM_REG_PERIODH].value; +} + +static void update_period_reg(void) +{ + hw.io_regs[TIM_REG_PERIODL].value = hw.curr_count & 0xFFFF; + hw.io_regs[TIM_REG_PERIODH].value = (hw.curr_count & 0xFFFF0000) >> 16; + //copy_snapshot(); +} + +static void decrease_counter(void) +{ + if (hw.curr_count > 2){ + hw.curr_count -= 2; + } + else { + hw.curr_count = 0; + } + update_period_reg(); +} + +static int32_t timer_can_decrease(void) +{ + int32_t ret = SIM_TRUE; + uint32_t reg_ctrl_val = hw.io_regs[TIM_REG_CTRL].value; + + if ((reg_ctrl_val & CTRL_START_MASK) == 0){ + ret = SIM_FALSE; + goto out; + } + + if ((reg_ctrl_val & CTRL_STOP_MASK) != 0){ + ret = SIM_FALSE; + goto out; + } + + if (hw.set_period == hw.curr_count){ + if ((reg_ctrl_val & CTRL_CONT_MASK) == 0){ + ret = SIM_FALSE; + goto out; + } + } +out: + return ret; +} + +static void update_status(void) +{ + if(hw.curr_count <= 0){ + hw.io_regs[TIM_REG_CTRL].value |= CTRL_ITO_MASK; + hw.curr_count = hw.set_period; + update_period_reg(); + hw.io_regs[TIM_REG_STATUS].value |= STATUS_TO_MASK; + } +} + +static void timer_simulate(struct io_device * self) +{ + if (timer_can_decrease() == SIM_TRUE) { + decrease_counter(); + update_status(); + } +} + +struct io_device timer_core = { + .name = "timer_core", + .init = timer_init, + .is_belong = timer_is_belong, + .read_data = timer_read, + .write_data = timer_write, + .has_irq = timer_has_irq, + .simulate = timer_simulate, + .irq_enable_mask = TIM_IRQ_MASK, +}; + + -- cgit v1.2.3-54-g00ecf