1 /* Implementation of SPIM compatible console device.
2 Copyright 2002, 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 "clock.h"
21 #include "mapper.h"
22 #include "spimconsole.h"
23 #include "spimconsreg.h"
24 #include "vmips.h"
25 #include <cassert>
26
SpimConsoleDevice(Clock * clock)27 SpimConsoleDevice::SpimConsoleDevice (Clock *clock)
28 : TerminalController (clock, KEYBOARD_POLL_NS, KEYBOARD_REPOLL_NS,
29 DISPLAY_READY_DELAY_NS),
30 DeviceMap (36),
31 trigger (0), clock_interrupt (false), clock_state (UNREADY)
32 {
33 display_interrupt_enable[0] = display_interrupt_enable[1] = false;
34 keyboard_interrupt_enable[0] = keyboard_interrupt_enable[1] = false;
35
36 trigger = new ClockTrigger( this );
37 clock->add_deferred_task( trigger, CLOCK_TRIGGER_NS );
38 }
39
~SpimConsoleDevice()40 SpimConsoleDevice::~SpimConsoleDevice()
41 {
42 assert( trigger );
43
44 trigger->cancel();
45 }
46
unready_display(int line,char data)47 void SpimConsoleDevice::unready_display( int line, char data )
48 {
49 TerminalController::unready_display( line, data );
50 deassertInt( line == 0 ? IRQ4 : IRQ6 );
51 }
52
ready_display(int line)53 void SpimConsoleDevice::ready_display( int line )
54 {
55 TerminalController::ready_display( line );
56 if( display_interrupt_enable[line] )
57 assertInt( line == 0 ? IRQ4 : IRQ6 );
58 }
59
unready_keyboard(int line)60 void SpimConsoleDevice::unready_keyboard( int line )
61 {
62 TerminalController::unready_keyboard( line );
63 deassertInt( line == 0 ? IRQ3 : IRQ5 );
64 }
65
ready_keyboard(int line)66 void SpimConsoleDevice::ready_keyboard( int line )
67 {
68 TerminalController::ready_keyboard( line );
69 if( keyboard_interrupt_enable[line] )
70 assertInt( line == 0 ? IRQ3 : IRQ5 );
71 }
72
unready_clock()73 void SpimConsoleDevice::unready_clock()
74 {
75 clock_state = UNREADY;
76 deassertInt( IRQ2 );
77 }
78
ready_clock()79 void SpimConsoleDevice::ready_clock()
80 {
81 clock_state = READY;
82
83 trigger = new ClockTrigger( this );
84 clock->add_deferred_task( trigger, CLOCK_TRIGGER_NS );
85
86 if( clock_interrupt )
87 assertInt( IRQ2 );
88 }
89
fetch_word(uint32 offset,int mode,DeviceExc * client)90 uint32 SpimConsoleDevice::fetch_word( uint32 offset, int mode,
91 DeviceExc *client)
92 {
93 uint32 word = 0;
94
95 switch( offset / 4 ) {
96 case 0: // keyboard 1 control
97 word = keyboard_interrupt_enable[0] ? CTL_IE : 0;
98 if( line_connected(0) )
99 word |= lines[0].keyboard_state;
100 if (!keyboard_interrupt_enable[0])
101 deassertInt (IRQ3);
102 break;
103 case 1: // keyboard 1 data
104 if( line_connected(0) ) {
105 unready_keyboard( 0 );
106 word = lines[0].keyboard_char;
107 }
108 break;
109 case 2: // display 1 control
110 word = display_interrupt_enable[0] ? CTL_IE : 0;
111 if( line_connected(0) )
112 word |= lines[0].display_state;
113 else
114 word |= CTL_RDY;
115 if (!display_interrupt_enable[0])
116 deassertInt (IRQ4);
117 break;
118 case 3: // display 1 data
119 break;
120 case 4: // keyboard 2 control
121 word = keyboard_interrupt_enable[1] ? CTL_IE : 0;
122 if( line_connected(1) )
123 word |= lines[1].keyboard_state;
124 if (!keyboard_interrupt_enable[1])
125 deassertInt (IRQ5);
126 break;
127 case 5: // keyboard 2 data
128 if( line_connected(1) ) {
129 unready_keyboard( 1 );
130 word = lines[1].keyboard_char;
131 }
132 break;
133 case 6: // display 2 control
134 word = display_interrupt_enable[1] ? CTL_IE : 0;
135 if( line_connected(1) )
136 word |= lines[1].display_state;
137 else
138 word |= CTL_RDY;
139 if (!display_interrupt_enable[1])
140 deassertInt (IRQ6);
141 break;
142 case 7: // display 2 data
143 break;
144 case 8: // clock control
145 word = clock_interrupt ? CTL_IE : 0;
146 word |= clock_state;
147 unready_clock();
148 break;
149 default:
150 assert( ! "reached" );
151 }
152 return machine->physmem->mips_to_host_word(word);
153 }
154
store_word(uint32 offset,uint32 odata,DeviceExc * client)155 void SpimConsoleDevice::store_word( uint32 offset, uint32 odata,
156 DeviceExc *client )
157 {
158 uint32 data = machine->physmem->host_to_mips_word(odata);
159
160 switch( offset / 4 ) {
161 case 0: // keyboard 1 control
162 keyboard_interrupt_enable[0] = data & CTL_IE;
163 if( line_connected(0) && keyboard_interrupt_enable[0]
164 && lines[0].display_state == READY )
165 assertInt( IRQ3 );
166 break;
167 case 1: // keyboard 1 data
168 break;
169 case 2: // display 1 control
170 display_interrupt_enable[0] = data & CTL_IE;
171 if( line_connected(0) && display_interrupt_enable[0]
172 && lines[0].display_state == READY )
173 assertInt( IRQ4 );
174 break;
175 case 3: // display 1 data
176 if( line_connected(0) )
177 unready_display( 0, data );
178 break;
179 case 4: // keyboard 2 control
180 keyboard_interrupt_enable[1] = data & CTL_IE;
181 if( line_connected(1) && keyboard_interrupt_enable[1] &&
182 lines[1].keyboard_state == READY )
183 assertInt( IRQ5 );
184 break;
185 case 5: // keyboard 2 data
186 break;
187 case 6: // display 2 control
188 display_interrupt_enable[1] = data & CTL_IE;
189 if( line_connected(1) && display_interrupt_enable[1] &&
190 lines[1].display_state == READY )
191 assertInt( IRQ6 );
192 break;
193 case 7: // display 2 data
194 if( line_connected(1) )
195 unready_display( 1, data );
196 break;
197 case 8: // clock control
198 clock_interrupt = data & CTL_IE;
199 if( clock_interrupt && clock_state == READY )
200 assertInt( IRQ2 );
201 break;
202 default:
203 assert( ! "reached" );
204 }
205 }
206
descriptor_str() const207 const char *SpimConsoleDevice::descriptor_str() const
208 {
209 return "SPIM console";
210 }
211
212
ClockTrigger(SpimConsoleDevice * console)213 SpimConsoleDevice::ClockTrigger::ClockTrigger( SpimConsoleDevice *console )
214 : console( console )
215 {
216 assert( console );
217 }
218
~ClockTrigger()219 SpimConsoleDevice::ClockTrigger::~ClockTrigger()
220 {
221 }
222
real_task()223 void SpimConsoleDevice::ClockTrigger::real_task()
224 {
225 console->ready_clock();
226 }
227