diff options
Diffstat (limited to 'uart_core.c')
-rw-r--r-- | uart_core.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/uart_core.c b/uart_core.c new file mode 100644 index 0000000..ae58154 --- /dev/null +++ b/uart_core.c @@ -0,0 +1,157 @@ +/* + 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 "public.h" +#include "niosii.h" +#include "io_device.h" +#include "uart_core.h" + +#define REG_RXDATA (0) +#define REG_TXDATA (1) +#define REG_STATUS (2) +#define REG_CONTROL (3) +#define REG_DIVISOR (4) +#define REG_ENDOFPACKET (5) + +static struct uart_core_hw hw; +static uint32_t valid_mask[UART_CORE_REG_CNT] = { + 0x1FF,0x1FF,0x1FFF,0x1FFF,0xFFFF,0x1FF +}; + +static uint32_t only_read_mask[UART_CORE_REG_CNT] = { + 0x1FF,0x00,0x00,0x00,0x00,0x00 +}; + +static void uart_init(struct io_device * self) +{ + int32_t i = 0; + + self->priv_data = &hw; + for (i=0;i<UART_CORE_REG_CNT; i++){ + hw.io_regs[i].addr = UART_CORE_BASE_ADDR + i * 4; + hw.io_regs[i].value = 0; + hw.io_regs[i].valid_mask = valid_mask[i]; + hw.io_regs[i].only_read_mask = only_read_mask[i]; + } + + hw.rx_status = 0; + hw.tx_status = 0; + printf("%s at 0x%08X-0x%08X\n",self->name, UART_CORE_BASE_ADDR, UART_CORE_BASE_ADDR + i * 4 - 4); +} + +static int32_t uart_is_belong(uint32_t address) +{ + int32_t ret_val = ADDR_IS_NOT_DEV; + + if ((address >= UART_CORE_BASE_ADDR) && (address < (UART_CORE_BASE_ADDR + UART_CORE_REG_CNT * 4))){ + ret_val = ADDR_IS_DEV; + } + return ret_val; +} + +static uint32_t uart_read(struct io_device * self, uint32_t addr, uint32_t data_len) +{ + uint32_t ret_val = 0; + uint32_t index = 0; + + index = (addr - UART_CORE_BASE_ADDR) / 4; + if (index >= 0 && index < UART_CORE_REG_CNT){ + ret_val = hw.io_regs[index].value & hw.io_regs[index].valid_mask; + ret_val = io_read_data(ret_val, data_len); + + if (index == REG_RXDATA){ + hw.rx_status = UART_HAS_NO_DATA_TO_RX; + hw.io_regs[REG_STATUS].value &= (~ALTERA_UART_STATUS_RRDY_MSK); + } + } + return ret_val; +} + +static void uart_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 - UART_CORE_BASE_ADDR) / 4; + + if (index >= 0 && index < UART_CORE_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 == REG_TXDATA){ + hw.tx_status = UART_HAS_DATA_TO_TX; + hw.io_regs[REG_STATUS].value &= (~ALTERA_UART_STATUS_TRDY_MSK); + } + } +} + +static int32_t uart_has_irq(struct io_device * self) +{ + int32_t ret_val = DEV_NO_IRQ; + uint32_t reg_ctrl_val = hw.io_regs[REG_CONTROL].value; + uint32_t reg_status_val = hw.io_regs[REG_STATUS].value; + + /* Check TX ready Interrupt */ + if (check_reg_bit(reg_ctrl_val, ALTERA_UART_CONTROL_TRDY_MSK) == SIM_TRUE){ + if (check_reg_bit(reg_status_val, ALTERA_UART_STATUS_TRDY_MSK) == SIM_TRUE){ + ret_val = DEV_HAS_IRQ; + } + } + + /* Check RX ready Interrupt */ + if (check_reg_bit(reg_ctrl_val, ALTERA_UART_CONTROL_RRDY_MSK) == SIM_TRUE){ + if (check_reg_bit(reg_status_val, ALTERA_UART_STATUS_RRDY_MSK) == SIM_TRUE){ + ret_val = DEV_HAS_IRQ; + } + } + + return ret_val; +} + +static void uart_simulate(struct io_device * self) +{ + /* handler TX */ + if (hw.tx_status == UART_HAS_DATA_TO_TX){ + hw.io_regs[REG_STATUS].value &= (~ALTERA_UART_STATUS_TRDY_MSK); + hw.tx_status = UART_HAS_NO_DATA_TO_TX; + /* Set status TRDY bit */ + hw.io_regs[REG_STATUS].value |= ALTERA_UART_STATUS_TRDY_MSK; + } + /* handler RX */ + if(hw.rx_status == UART_HAS_NO_DATA_TO_RX){ + /* ToDo: Get the input data */ + hw.rx_status = UART_HAS_DATA_TO_RX; + /* Set status RRDY bit */ + hw.io_regs[REG_STATUS].value |= ALTERA_UART_STATUS_RRDY_MSK; + } +} + +struct io_device uart_core = { + .name = "UART Core", + .init = uart_init, + .is_belong = uart_is_belong, + .read_data = uart_read, + .write_data = uart_write, + .has_irq = uart_has_irq, + .simulate = uart_simulate, + .irq_enable_mask = UART_IRQ_MASK, +}; |