1 /* Implementation of VMIPS clock device.
2 Copyright 2003 Paul Twohey.
3
4 This file is part of VMIPS.
5
6 VMIPS is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2 of the License, or (at your
9 option) any later version.
10
11 VMIPS is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with VMIPS; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 #include "clockdev.h"
21 #include "devreg.h"
22
23 #include <cassert>
24 #include <cstddef>
25
ClockDevice(Clock * clock,uint32 irq,long frequency_ns)26 ClockDevice::ClockDevice( Clock *clock, uint32 irq, long frequency_ns )
27 : DeviceMap(20), irq(irq), frequency_ns(frequency_ns),
28 clock(clock), clock_trigger(0), clock_state(UNREADY),
29 interrupt_enabled(false)
30 {
31 assert (clock && "ClockDevice initialized with null Clock");
32 assert (frequency_ns > 0
33 && "ClockDevice initialized with non-positive frequency");
34 assert (irq != IRQ0 && irq != IRQ1
35 && "ClockDevice initialized with invalid IRQ");
36
37 clock_trigger = new ClockTrigger(this);
38 clock->add_deferred_task( clock_trigger, frequency_ns );
39 }
40
~ClockDevice()41 ClockDevice::~ClockDevice()
42 {
43 assert( clock_trigger );
44
45 clock_trigger->cancel();
46 clock_trigger = NULL;
47 }
48
ready_clock()49 void ClockDevice::ready_clock()
50 {
51 clock_state = READY;
52
53 if( interrupt_enabled )
54 assertInt( irq );
55
56 clock_trigger = new ClockTrigger( this );
57 clock->add_deferred_task( clock_trigger, frequency_ns );
58 }
59
unready_clock()60 void ClockDevice::unready_clock()
61 {
62 clock_state = UNREADY;
63 deassertInt( irq );
64 }
65
fetch_word(uint32 offset,int mode,DeviceExc * client)66 uint32 ClockDevice::fetch_word( uint32 offset, int mode, DeviceExc *client )
67 {
68 switch( offset / 4 ) {
69 case 0: // real time - seconds
70 timeval real_time;
71 gettimeofday( &real_time, NULL );
72 return real_time.tv_sec;
73 break;
74 case 1: // real time - microseconds
75 gettimeofday( &real_time, NULL );
76 return real_time.tv_usec;
77 break;
78 case 2: // simulated time - seconds
79 return clock->get_time().tv_sec;
80 break;
81 case 3: // simulated time - microseconds
82 return clock->get_time().tv_nsec / 1000;
83 break;
84 case 4: // control word
85 {
86 uint32 word = interrupt_enabled ? CTL_RDY : 0;
87 word |= clock_state;
88 unready_clock();
89 return word;
90 break;
91 }
92 default:
93 assert( ! "reached" );
94 return 0;
95 }
96 }
97
store_word(uint32 offset,uint32 data,DeviceExc * client)98 void ClockDevice::store_word( uint32 offset, uint32 data, DeviceExc *client )
99 {
100 switch( offset / 4 ) {
101 case 0: // real time - seconds
102 case 1: // real time - micro seconds
103 return;
104 case 2: // simulated time - seconds
105 {
106 if( (int32)data < 0 )
107 return;
108
109 timespec time;
110 time.tv_sec = data;
111 time.tv_nsec = clock->get_time().tv_nsec;
112 clock->set_time( time );
113 return;
114 }
115 case 3: // simulated time - micro seconds
116 {
117 if( (int32)data < 0 )
118 return;
119
120 timespec time;
121 time.tv_sec = clock->get_time().tv_sec;
122 time.tv_nsec = data;
123 clock->set_time( time );
124 return;
125 }
126 case 4: // control word
127 interrupt_enabled = data & CTL_IE;
128 if( interrupt_enabled && clock_state == READY )
129 assertInt( irq );
130 return;
131 default:
132 assert( ! "reached" );
133 }
134 }
135
descriptor_str() const136 const char *ClockDevice::descriptor_str() const
137 {
138 return "Clock device";
139 }
140
141
ClockTrigger(ClockDevice * clock_device)142 ClockDevice::ClockTrigger::ClockTrigger( ClockDevice *clock_device )
143 : clock_device( clock_device )
144 {
145 assert( clock_device );
146 }
147
~ClockTrigger()148 ClockDevice::ClockTrigger::~ClockTrigger()
149 {
150 }
151
real_task()152 void ClockDevice::ClockTrigger::real_task()
153 {
154 clock_device->ready_clock();
155 }
156