Home | History | Annotate | Line # | Download | only in lm32
      1 /*  Lattice Mico32 timer model.
      2     Contributed by Jon Beniston <jon (at) beniston.com>
      3 
      4    Copyright (C) 2009-2024 Free Software Foundation, Inc.
      5 
      6    This file is part of GDB.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20 
     21 /* This must come before any other includes.  */
     22 #include "defs.h"
     23 
     24 #include "sim-main.h"
     25 #include "hw-main.h"
     26 #include "sim-assert.h"
     27 
     28 struct lm32timer
     29 {
     30   unsigned base;		/* Base address of this timer.  */
     31   unsigned limit;		/* Limit address of this timer.  */
     32   unsigned int status;
     33   unsigned int control;
     34   unsigned int period;
     35   unsigned int snapshot;
     36   struct hw_event *event;
     37 };
     38 
     39 /* Timer registers.  */
     40 #define LM32_TIMER_STATUS       0x0
     41 #define LM32_TIMER_CONTROL      0x4
     42 #define LM32_TIMER_PERIOD       0x8
     43 #define LM32_TIMER_SNAPSHOT     0xc
     44 
     45 /* Timer ports.  */
     46 
     47 enum
     48 {
     49   INT_PORT
     50 };
     51 
     52 static const struct hw_port_descriptor lm32timer_ports[] = {
     53   {"int", INT_PORT, 0, output_port},
     54   {}
     55 };
     56 
     57 static void
     58 do_timer_event (struct hw *me, void *data)
     59 {
     60   struct lm32timer *timer = hw_data (me);
     61 
     62   /* Is timer started? */
     63   if (timer->control & 0x4)
     64     {
     65       if (timer->snapshot)
     66 	{
     67 	  /* Decrement timer.  */
     68 	  timer->snapshot--;
     69 	}
     70       else if (timer->control & 1)
     71 	{
     72 	  /* Restart timer.  */
     73 	  timer->snapshot = timer->period;
     74 	}
     75     }
     76   /* Generate interrupt when timer is at 0, and interrupt enable is 1.  */
     77   if ((timer->snapshot == 0) && (timer->control & 1))
     78     {
     79       /* Generate interrupt.  */
     80       hw_port_event (me, INT_PORT, 1);
     81     }
     82   /* If timer is started, schedule another event to decrement the timer again.  */
     83   if (timer->control & 4)
     84     hw_event_queue_schedule (me, 1, do_timer_event, 0);
     85 }
     86 
     87 static unsigned
     88 lm32timer_io_write_buffer (struct hw *me,
     89 			   const void *source,
     90 			   int space, unsigned_word base, unsigned nr_bytes)
     91 {
     92   struct lm32timer *timers = hw_data (me);
     93   int timer_reg;
     94   const unsigned char *source_bytes = source;
     95   int value = 0;
     96 
     97   HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base,
     98 	     (int) nr_bytes, value));
     99 
    100   if (nr_bytes == 4)
    101     value = (source_bytes[0] << 24)
    102       | (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]);
    103   else
    104     hw_abort (me, "write with invalid number of bytes: %d", nr_bytes);
    105 
    106   timer_reg = base - timers->base;
    107 
    108   switch (timer_reg)
    109     {
    110     case LM32_TIMER_STATUS:
    111       timers->status = value;
    112       break;
    113     case LM32_TIMER_CONTROL:
    114       timers->control = value;
    115       if (timers->control & 0x4)
    116 	{
    117 	  /* Timer is started.  */
    118 	  hw_event_queue_schedule (me, 1, do_timer_event, 0);
    119 	}
    120       break;
    121     case LM32_TIMER_PERIOD:
    122       timers->period = value;
    123       break;
    124     default:
    125       hw_abort (me, "invalid register address: 0x%x.", timer_reg);
    126     }
    127 
    128   return nr_bytes;
    129 }
    130 
    131 static unsigned
    132 lm32timer_io_read_buffer (struct hw *me,
    133 			  void *dest,
    134 			  int space, unsigned_word base, unsigned nr_bytes)
    135 {
    136   struct lm32timer *timers = hw_data (me);
    137   int timer_reg;
    138   int value;
    139   unsigned char *dest_bytes = dest;
    140 
    141   HW_TRACE ((me, "read 0x%08lx length %d", (long) base, (int) nr_bytes));
    142 
    143   timer_reg = base - timers->base;
    144 
    145   switch (timer_reg)
    146     {
    147     case LM32_TIMER_STATUS:
    148       value = timers->status;
    149       break;
    150     case LM32_TIMER_CONTROL:
    151       value = timers->control;
    152       break;
    153     case LM32_TIMER_PERIOD:
    154       value = timers->period;
    155       break;
    156     case LM32_TIMER_SNAPSHOT:
    157       value = timers->snapshot;
    158       break;
    159     default:
    160       hw_abort (me, "invalid register address: 0x%x.", timer_reg);
    161     }
    162 
    163   if (nr_bytes == 4)
    164     {
    165       dest_bytes[0] = value >> 24;
    166       dest_bytes[1] = value >> 16;
    167       dest_bytes[2] = value >> 8;
    168       dest_bytes[3] = value;
    169     }
    170   else
    171     hw_abort (me, "read of unsupported number of bytes: %d", nr_bytes);
    172 
    173   return nr_bytes;
    174 }
    175 
    176 static void
    177 attach_lm32timer_regs (struct hw *me, struct lm32timer *timers)
    178 {
    179   unsigned_word attach_address;
    180   int attach_space;
    181   unsigned attach_size;
    182   reg_property_spec reg;
    183 
    184   if (hw_find_property (me, "reg") == NULL)
    185     hw_abort (me, "Missing \"reg\" property");
    186   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    187     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    188   hw_unit_address_to_attach_address (hw_parent (me),
    189 				     &reg.address,
    190 				     &attach_space, &attach_address, me);
    191   timers->base = attach_address;
    192   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    193   timers->limit = attach_address + (attach_size - 1);
    194   hw_attach_address (hw_parent (me),
    195 		     0, attach_space, attach_address, attach_size, me);
    196 }
    197 
    198 static void
    199 lm32timer_finish (struct hw *me)
    200 {
    201   struct lm32timer *timers;
    202 
    203   timers = HW_ZALLOC (me, struct lm32timer);
    204   set_hw_data (me, timers);
    205   set_hw_io_read_buffer (me, lm32timer_io_read_buffer);
    206   set_hw_io_write_buffer (me, lm32timer_io_write_buffer);
    207   set_hw_ports (me, lm32timer_ports);
    208 
    209   /* Attach ourself to our parent bus.  */
    210   attach_lm32timer_regs (me, timers);
    211 
    212   /* Initialize the timers.  */
    213   timers->status = 0;
    214   timers->control = 0;
    215   timers->period = 0;
    216   timers->snapshot = 0;
    217 }
    218 
    219 const struct hw_descriptor dv_lm32timer_descriptor[] = {
    220   {"lm32timer", lm32timer_finish,},
    221   {NULL},
    222 };
    223