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