1a1ba9ba4Schristos /* Blackfin Watchpoint (WP) model.
2a1ba9ba4Schristos 
3*184b2d41Schristos    Copyright (C) 2010-2020 Free Software Foundation, Inc.
4a1ba9ba4Schristos    Contributed by Analog Devices, Inc.
5a1ba9ba4Schristos 
6a1ba9ba4Schristos    This file is part of simulators.
7a1ba9ba4Schristos 
8a1ba9ba4Schristos    This program is free software; you can redistribute it and/or modify
9a1ba9ba4Schristos    it under the terms of the GNU General Public License as published by
10a1ba9ba4Schristos    the Free Software Foundation; either version 3 of the License, or
11a1ba9ba4Schristos    (at your option) any later version.
12a1ba9ba4Schristos 
13a1ba9ba4Schristos    This program is distributed in the hope that it will be useful,
14a1ba9ba4Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
15a1ba9ba4Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a1ba9ba4Schristos    GNU General Public License for more details.
17a1ba9ba4Schristos 
18a1ba9ba4Schristos    You should have received a copy of the GNU General Public License
19a1ba9ba4Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20a1ba9ba4Schristos 
21a1ba9ba4Schristos #include "config.h"
22a1ba9ba4Schristos 
23a1ba9ba4Schristos #include "sim-main.h"
24a1ba9ba4Schristos #include "devices.h"
25a1ba9ba4Schristos #include "dv-bfin_wp.h"
26a1ba9ba4Schristos 
27a1ba9ba4Schristos /* XXX: This is mostly a stub.  */
28a1ba9ba4Schristos 
29a1ba9ba4Schristos #define WPI_NUM 6	/* 6 instruction watchpoints.  */
30a1ba9ba4Schristos #define WPD_NUM 2	/* 2 data watchpoints.  */
31a1ba9ba4Schristos 
32a1ba9ba4Schristos struct bfin_wp
33a1ba9ba4Schristos {
34a1ba9ba4Schristos   bu32 base;
35a1ba9ba4Schristos 
36a1ba9ba4Schristos   /* Order after here is important -- matches hardware MMR layout.  */
37a1ba9ba4Schristos   bu32 iactl;
38a1ba9ba4Schristos   bu32 _pad0[15];
39a1ba9ba4Schristos   bu32 ia[WPI_NUM];
40a1ba9ba4Schristos   bu32 _pad1[16 - WPI_NUM];
41a1ba9ba4Schristos   bu32 iacnt[WPI_NUM];
42a1ba9ba4Schristos   bu32 _pad2[32 - WPI_NUM];
43a1ba9ba4Schristos 
44a1ba9ba4Schristos   bu32 dactl;
45a1ba9ba4Schristos   bu32 _pad3[15];
46a1ba9ba4Schristos   bu32 da[WPD_NUM];
47a1ba9ba4Schristos   bu32 _pad4[16 - WPD_NUM];
48a1ba9ba4Schristos   bu32 dacnt[WPD_NUM];
49a1ba9ba4Schristos   bu32 _pad5[32 - WPD_NUM];
50a1ba9ba4Schristos 
51a1ba9ba4Schristos   bu32 stat;
52a1ba9ba4Schristos };
53a1ba9ba4Schristos #define mmr_base()      offsetof(struct bfin_wp, iactl)
54a1ba9ba4Schristos #define mmr_offset(mmr) (offsetof(struct bfin_wp, mmr) - mmr_base())
55a1ba9ba4Schristos #define mmr_idx(mmr)    (mmr_offset (mmr) / 4)
56a1ba9ba4Schristos 
57a1ba9ba4Schristos static const char * const mmr_names[] =
58a1ba9ba4Schristos {
59a1ba9ba4Schristos   [mmr_idx (iactl)] = "WPIACTL",
60a1ba9ba4Schristos   [mmr_idx (ia)]    = "WPIA0", "WPIA1", "WPIA2", "WPIA3", "WPIA4", "WPIA5",
61a1ba9ba4Schristos   [mmr_idx (iacnt)] = "WPIACNT0", "WPIACNT1", "WPIACNT2",
62a1ba9ba4Schristos 		      "WPIACNT3", "WPIACNT4", "WPIACNT5",
63a1ba9ba4Schristos   [mmr_idx (dactl)] = "WPDACTL",
64a1ba9ba4Schristos   [mmr_idx (da)]    = "WPDA0", "WPDA1", "WPDA2", "WPDA3", "WPDA4", "WPDA5",
65a1ba9ba4Schristos   [mmr_idx (dacnt)] = "WPDACNT0", "WPDACNT1", "WPDACNT2",
66a1ba9ba4Schristos 		      "WPDACNT3", "WPDACNT4", "WPDACNT5",
67a1ba9ba4Schristos   [mmr_idx (stat)]  = "WPSTAT",
68a1ba9ba4Schristos };
69a1ba9ba4Schristos #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
70a1ba9ba4Schristos 
71a1ba9ba4Schristos static unsigned
bfin_wp_io_write_buffer(struct hw * me,const void * source,int space,address_word addr,unsigned nr_bytes)72a1ba9ba4Schristos bfin_wp_io_write_buffer (struct hw *me, const void *source, int space,
73a1ba9ba4Schristos 			 address_word addr, unsigned nr_bytes)
74a1ba9ba4Schristos {
75a1ba9ba4Schristos   struct bfin_wp *wp = hw_data (me);
76a1ba9ba4Schristos   bu32 mmr_off;
77a1ba9ba4Schristos   bu32 value;
78a1ba9ba4Schristos   bu32 *valuep;
79a1ba9ba4Schristos 
80b2396a7bSchristos   /* Invalid access mode is higher priority than missing register.  */
81b2396a7bSchristos   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
82b2396a7bSchristos     return 0;
83b2396a7bSchristos 
84a1ba9ba4Schristos   value = dv_load_4 (source);
85a1ba9ba4Schristos   mmr_off = addr - wp->base;
86a1ba9ba4Schristos   valuep = (void *)((unsigned long)wp + mmr_base() + mmr_off);
87a1ba9ba4Schristos 
88a1ba9ba4Schristos   HW_TRACE_WRITE ();
89a1ba9ba4Schristos 
90a1ba9ba4Schristos   switch (mmr_off)
91a1ba9ba4Schristos     {
92a1ba9ba4Schristos     case mmr_offset(iactl):
93a1ba9ba4Schristos     case mmr_offset(ia[0]) ... mmr_offset(ia[WPI_NUM - 1]):
94a1ba9ba4Schristos     case mmr_offset(iacnt[0]) ... mmr_offset(iacnt[WPI_NUM - 1]):
95a1ba9ba4Schristos     case mmr_offset(dactl):
96a1ba9ba4Schristos     case mmr_offset(da[0]) ... mmr_offset(da[WPD_NUM - 1]):
97a1ba9ba4Schristos     case mmr_offset(dacnt[0]) ... mmr_offset(dacnt[WPD_NUM - 1]):
98a1ba9ba4Schristos       *valuep = value;
99a1ba9ba4Schristos       break;
100a1ba9ba4Schristos     case mmr_offset(stat):
101a1ba9ba4Schristos       /* Yes, the hardware is this dumb -- clear all bits on any write.  */
102a1ba9ba4Schristos       *valuep = 0;
103a1ba9ba4Schristos       break;
104a1ba9ba4Schristos     default:
105a1ba9ba4Schristos       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
106b2396a7bSchristos       return 0;
107a1ba9ba4Schristos     }
108a1ba9ba4Schristos 
109a1ba9ba4Schristos   return nr_bytes;
110a1ba9ba4Schristos }
111a1ba9ba4Schristos 
112a1ba9ba4Schristos static unsigned
bfin_wp_io_read_buffer(struct hw * me,void * dest,int space,address_word addr,unsigned nr_bytes)113a1ba9ba4Schristos bfin_wp_io_read_buffer (struct hw *me, void *dest, int space,
114a1ba9ba4Schristos 			address_word addr, unsigned nr_bytes)
115a1ba9ba4Schristos {
116a1ba9ba4Schristos   struct bfin_wp *wp = hw_data (me);
117a1ba9ba4Schristos   bu32 mmr_off;
118a1ba9ba4Schristos   bu32 value;
119a1ba9ba4Schristos   bu32 *valuep;
120a1ba9ba4Schristos 
121b2396a7bSchristos   /* Invalid access mode is higher priority than missing register.  */
122b2396a7bSchristos   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, false))
123b2396a7bSchristos     return 0;
124b2396a7bSchristos 
125a1ba9ba4Schristos   mmr_off = addr - wp->base;
126a1ba9ba4Schristos   valuep = (void *)((unsigned long)wp + mmr_base() + mmr_off);
127a1ba9ba4Schristos 
128a1ba9ba4Schristos   HW_TRACE_READ ();
129a1ba9ba4Schristos 
130a1ba9ba4Schristos   switch (mmr_off)
131a1ba9ba4Schristos     {
132a1ba9ba4Schristos     case mmr_offset(iactl):
133a1ba9ba4Schristos     case mmr_offset(ia[0]) ... mmr_offset(ia[WPI_NUM - 1]):
134a1ba9ba4Schristos     case mmr_offset(iacnt[0]) ... mmr_offset(iacnt[WPI_NUM - 1]):
135a1ba9ba4Schristos     case mmr_offset(dactl):
136a1ba9ba4Schristos     case mmr_offset(da[0]) ... mmr_offset(da[WPD_NUM - 1]):
137a1ba9ba4Schristos     case mmr_offset(dacnt[0]) ... mmr_offset(dacnt[WPD_NUM - 1]):
138a1ba9ba4Schristos     case mmr_offset(stat):
139a1ba9ba4Schristos       value = *valuep;
140a1ba9ba4Schristos       break;
141a1ba9ba4Schristos     default:
142a1ba9ba4Schristos       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
143b2396a7bSchristos       return 0;
144a1ba9ba4Schristos     }
145a1ba9ba4Schristos 
146a1ba9ba4Schristos   dv_store_4 (dest, value);
147a1ba9ba4Schristos 
148a1ba9ba4Schristos   return nr_bytes;
149a1ba9ba4Schristos }
150a1ba9ba4Schristos 
151a1ba9ba4Schristos static void
attach_bfin_wp_regs(struct hw * me,struct bfin_wp * wp)152a1ba9ba4Schristos attach_bfin_wp_regs (struct hw *me, struct bfin_wp *wp)
153a1ba9ba4Schristos {
154a1ba9ba4Schristos   address_word attach_address;
155a1ba9ba4Schristos   int attach_space;
156a1ba9ba4Schristos   unsigned attach_size;
157a1ba9ba4Schristos   reg_property_spec reg;
158a1ba9ba4Schristos 
159a1ba9ba4Schristos   if (hw_find_property (me, "reg") == NULL)
160a1ba9ba4Schristos     hw_abort (me, "Missing \"reg\" property");
161a1ba9ba4Schristos 
162a1ba9ba4Schristos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
163a1ba9ba4Schristos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
164a1ba9ba4Schristos 
165a1ba9ba4Schristos   hw_unit_address_to_attach_address (hw_parent (me),
166a1ba9ba4Schristos 				     &reg.address,
167a1ba9ba4Schristos 				     &attach_space, &attach_address, me);
168a1ba9ba4Schristos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
169a1ba9ba4Schristos 
170a1ba9ba4Schristos   if (attach_size != BFIN_COREMMR_WP_SIZE)
171a1ba9ba4Schristos     hw_abort (me, "\"reg\" size must be %#x", BFIN_COREMMR_WP_SIZE);
172a1ba9ba4Schristos 
173a1ba9ba4Schristos   hw_attach_address (hw_parent (me),
174a1ba9ba4Schristos 		     0, attach_space, attach_address, attach_size, me);
175a1ba9ba4Schristos 
176a1ba9ba4Schristos   wp->base = attach_address;
177a1ba9ba4Schristos }
178a1ba9ba4Schristos 
179a1ba9ba4Schristos static void
bfin_wp_finish(struct hw * me)180a1ba9ba4Schristos bfin_wp_finish (struct hw *me)
181a1ba9ba4Schristos {
182a1ba9ba4Schristos   struct bfin_wp *wp;
183a1ba9ba4Schristos 
184a1ba9ba4Schristos   wp = HW_ZALLOC (me, struct bfin_wp);
185a1ba9ba4Schristos 
186a1ba9ba4Schristos   set_hw_data (me, wp);
187a1ba9ba4Schristos   set_hw_io_read_buffer (me, bfin_wp_io_read_buffer);
188a1ba9ba4Schristos   set_hw_io_write_buffer (me, bfin_wp_io_write_buffer);
189a1ba9ba4Schristos 
190a1ba9ba4Schristos   attach_bfin_wp_regs (me, wp);
191a1ba9ba4Schristos }
192a1ba9ba4Schristos 
193a1ba9ba4Schristos const struct hw_descriptor dv_bfin_wp_descriptor[] =
194a1ba9ba4Schristos {
195a1ba9ba4Schristos   {"bfin_wp", bfin_wp_finish,},
196a1ba9ba4Schristos   {NULL, NULL},
197a1ba9ba4Schristos };
198