xref: /haiku/src/system/kernel/platform/atari_m68k/platform.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
1 /*
2 	Atari kernel platform code.
3 */
4 
5 #include <arch_platform.h>
6 
7 #include <new>
8 #include <util/kernel_cpp.h>
9 
10 #include <KernelExport.h>
11 
12 #include <boot/kernel_args.h>
13 #include <arch/cpu.h>
14 //#include <platform/openfirmware/openfirmware.h>
15 #include <platform/atari_m68k/MFP.h>
16 #include <platform/atari_m68k/platform_atari_m68k.h>
17 #include <real_time_clock.h>
18 #include <timer.h>
19 
20 #include "debugger_keymaps.h"
21 
22 /* which MFP timer to use */
23 #define SYS_TDR		MFP_TADR
24 #define SYS_TCR		MFP_TACR
25 #define SYS_TCRMASK	0x0f	/* mask for timer control (0xf for A&B, 0x7 for C, 0x38 for D) */
26 #define SYS_TENABLE	0x01	/* delay mode with /4 prescaler: 0x01 (<<3 for timer D) */
27 #define SYS_TDISABLE	0x00
28 #define SYS_TVECTOR	13
29 #define MFP_PRESCALER	4
30 
31 /* used for timer interrupt */
32 #define MFP_TIMER_RATE	(MFP_FREQ/MFP_PRESCALER)
33 #define MFP_MAX_TIMER_INTERVAL	(0xff * 1000000L / MFP_TIMER_RATE)
34 
35 /* used for system_time() calculation */
36 #define MFP_SYSTEM_TIME_RATE	(MFP_FREQ/MFP_PRESCALER)
37 
38 
39 #define MFP0_BASE	0xFFFFFA00
40 #define MFP1_BASE	0xFFFFFA80
41 
42 #define MFP0_VECTOR_BASE	64
43 #define MFP1_VECTOR_BASE	(MFP0_VECTOR_BASE+16)
44 
45 #define TT_RTC_BASE	0xFFFF8960
46 
47 #define TT_RTC_VECTOR	(MFP1_VECTOR_BASE+14)
48 
49 // ?
50 #define SCC_C0_VECTOR_BASE	(MFP1_VECTOR_BASE+16)
51 // ??
52 #define SCC_C1_VECTOR_BASE	(0x1BC/4)
53 
54 #define IKBD_BASE	0xFFFFFC00
55 #define IKBD_CTRL	0
56 #define IKBD_DATA	2
57 #define IKBD_STATUS_READ_BUFFER_FULL	0x01
58 
59 // keyboard scancodes, very much like PC ones
60 // see
61 // http://www.classiccmp.org/dunfield/atw800/h/atw800k.jpg
62 // ST Mag Nr 57 page 55
63 enum keycodes {
64 	LEFT_SHIFT		= 42,
65 	RIGHT_SHIFT		= 54,
66 
67 	LEFT_CONTROL	= 29,
68 
69 	LEFT_ALT		= 56,
70 
71 	CURSOR_LEFT		= 75,
72 	CURSOR_RIGHT	= 77,
73 	CURSOR_UP		= 72,
74 	CURSOR_DOWN		= 80,
75 	CURSOR_HOME		= 71,
76 	CURSOR_END		= 79,	// not on real atari keyboard
77 	PAGE_UP			= 73,	// not on real atari keyboard XXX remap Help ?
78 	PAGE_DOWN		= 81,	// not on real atari keyboard XXX remap Undo ?
79 
80 	DELETE			= 83,
81 	F12				= 88,	// but it's shifted
82 
83 };
84 
85 #define in8(a)  (*(volatile uint8 *)(a))
86 #define out8(v, a)  (*(volatile uint8 *)(a) = v)
87 
88 
89 namespace BPrivate {
90 
91 //class MfpPIC;
92 
93 // #pragma mark - Atari (Falcon)
94 
95 
96 class M68KAtari : public M68KPlatform {
97 public:
98 	class MFP {
99 	public:
100 		MFP(uint32 base, int vector);
101 		~MFP();
102 
103 		uint32 Base() const { return fBase; };
104 		int Vector() const { return fVector; };
105 
106 		uint8 ReadReg(uint32 reg) { return in8(fBase + reg); };
107 		void WriteReg(uint32 reg, uint8 v) { out8(v, fBase + reg); };
108 
109 		void EnableIOInterrupt(int32 irq);
110 		void DisableIOInterrupt(int32 irq);
111 		bool AcknowledgeIOInterrupt(int32 irq);
112 
113 	private:
114 		uint32 fBase;
115 		int fVector;
116 	};
117 
118 	class RTC {
119 	public:
120 		RTC(uint32 base, int vector);
121 		~RTC();
122 
123 		uint32 Base() const { return fBase; };
124 		int Vector() const { return fVector; };
125 
126 		uint8 ReadReg(uint32 reg);
127 		void WriteReg(uint32 reg, uint8 v) { out8((uint8)reg,fBase+1); out8(v,fBase+3); };
128 
129 	private:
130 		uint32 fBase;
131 		int fVector;
132 	};
133 
134 	M68KAtari();
135 	virtual ~M68KAtari();
136 
137 	void ProbeHardware(struct kernel_args *kernelArgs);
138 
139 	virtual status_t Init(struct kernel_args *kernelArgs);
140 	virtual status_t InitSerialDebug(struct kernel_args *kernelArgs);
141 	virtual status_t InitPostVM(struct kernel_args *kernelArgs);
142 	virtual status_t InitPIC(struct kernel_args *kernelArgs);
143 	virtual status_t InitRTC(struct kernel_args *kernelArgs,
144 		struct real_time_data *data);
145 	virtual status_t InitTimer(struct kernel_args *kernelArgs);
146 
147 	virtual char BlueScreenGetChar();
148 
149 	virtual char SerialDebugGetChar();
150 	virtual void SerialDebugPutChar(char c);
151 
152 	virtual void EnableIOInterrupt(int32 irq);
153 	virtual void DisableIOInterrupt(int32 irq);
154 	virtual bool AcknowledgeIOInterrupt(int32 irq);
155 
156 	virtual	uint8 ReadRTCReg(uint8 reg);
157 	virtual	void WriteRTCReg(uint8 reg, uint8 val);
158 	virtual	void SetHardwareRTC(uint32 seconds);
159 	virtual	uint32 GetHardwareRTC();
160 
161 	virtual void SetHardwareTimer(bigtime_t timeout);
162 	virtual void ClearHardwareTimer(void);
163 
164 	virtual	void ShutDown(bool reboot);
165 
166 private:
167 	MFP	*MFPForIrq(int irq);
168 	static int32	MFPTimerInterrupt(void *data);
169 
170 	MFP	*fMFP[2];
171 
172 	RTC	*fRTC;
173 
174 	// native features (ARAnyM emulator)
175 	uint32 (*nfGetID)(const char *name);
176 	int32 (*nfCall)(uint32 ID, ...);
177 	char *nfPage;
178 	uint32 nfDebugPrintfID;
179 
180 };
181 
182 
183 }	// namespace BPrivate
184 
185 using BPrivate::M68KAtari;
186 
187 
188 // #pragma mark - M68KAtari::MFP
189 
190 
191 static char sMFP0Buffer[sizeof(M68KAtari::MFP)];
192 static char sMFP1Buffer[sizeof(M68KAtari::MFP)];
193 
194 // constructor
195 M68KAtari::MFP::MFP(uint32 base, int vector)
196 {
197 	fBase = base;
198 	fVector = vector;
199 }
200 
201 
202 M68KAtari::MFP::~MFP()
203 {
204 }
205 
206 #warning M68K: use enable or mark register ?
207 
208 void
209 M68KAtari::MFP::EnableIOInterrupt(int irq)
210 {
211 	uint8 bit = 1 << (irq % 8);
212 	// I*B[0] is vector+0, I*A[0] is vector+8
213 	uint32 reg = Base() + ((irq > 8) ? (MFP_IERA) : (MFP_IERB));
214 	uint8 val = in8(reg);
215 	if (val & bit == 0) {
216 		val |= bit;
217 		out8(val, reg);
218 	}
219 }
220 
221 
222 void
223 M68KAtari::MFP::DisableIOInterrupt(int irq)
224 {
225 	uint8 bit = 1 << (irq % 8);
226 	// I*B[0] is vector+0, I*A[0] is vector+8
227 	uint32 reg = Base() + ((irq > 8) ? (MFP_IERA) : (MFP_IERB));
228 	uint8 val = in8(reg);
229 	if (val & bit) {
230 		val &= ~bit;
231 		out8(val, reg);
232 	}
233 }
234 
235 
236 bool
237 M68KAtari::MFP::AcknowledgeIOInterrupt(int irq)
238 {
239 	uint8 bit = 1 << (irq % 8);
240 	// I*B[0] is vector+0, I*A[0] is vector+8
241 	uint32 reg = Base() + ((irq > 8) ? (MFP_ISRA) : (MFP_ISRB));
242 	uint8 val = in8(reg);
243 	if (val & bit) {
244 		val &= ~bit;
245 		out8(val, reg);
246 		return true;
247 	}
248 	return false;
249 }
250 
251 
252 // #pragma mark - M68KAtari::RTc
253 
254 
255 static char sRTCBuffer[sizeof(M68KAtari::RTC)];
256 
257 // constructor
258 M68KAtari::RTC::RTC(uint32 base, int vector)
259 {
260 	fBase = base;
261 	fVector = vector;
262 }
263 
264 
265 M68KAtari::RTC::~RTC()
266 {
267 }
268 
269 
270 uint8
271 M68KAtari::RTC::ReadReg(uint32 reg)
272 {
273 	int waitTime = 10000;
274 
275 	if (reg < 0x0a) {	// time of day stuff...
276 				// check for in progress updates before accessing
277 		out8(0x0a, fBase+1);
278 		while((in8(fBase+3) & 0x80) && --waitTime);
279 	}
280 
281 	out8((uint8)reg,fBase+1);
282 	return in8(fBase+3);
283 }
284 
285 
286 // #pragma mark - M68KAtari
287 
288 
289 // constructor
290 M68KAtari::M68KAtari()
291 	: M68KPlatform(M68K_PLATFORM_ATARI)
292 {
293 }
294 
295 
296 // destructor
297 M68KAtari::~M68KAtari()
298 {
299 }
300 
301 
302 void
303 M68KAtari::ProbeHardware(struct kernel_args *kernelArgs)
304 {
305 	dprintf("Atari hardware:\n");
306 	// if we are here we already know we have one
307 	dprintf("	ST MFP\n");
308 	if (m68k_is_hw_register_readable(MFP1_BASE)) {
309 		dprintf("	TT MFP\n");
310 		fMFP[1] = new(sMFP1Buffer) M68KAtari::MFP(MFP1_BASE, MFP1_VECTOR_BASE);
311 	}
312 	if (m68k_is_hw_register_readable(TT_RTC_BASE)) {
313 		dprintf("	TT RTC MC146818A\n");
314 		fRTC = new(sRTCBuffer) M68KAtari::RTC(TT_RTC_BASE,TT_RTC_VECTOR);
315 	} else
316 		panic("TT RTC required!");
317 }
318 
319 
320 status_t
321 M68KAtari::Init(struct kernel_args *kernelArgs)
322 {
323 	fMFP[0] = NULL;
324 	fMFP[1] = NULL;
325 	fRTC = NULL;
326 
327 	// initialize ARAnyM NatFeatures
328 	nfGetID =
329 		kernelArgs->arch_args.plat_args.atari.nat_feat.nf_get_id;
330 	nfCall =
331 		kernelArgs->arch_args.plat_args.atari.nat_feat.nf_call;
332 	nfPage = (char *)
333 		kernelArgs->arch_args.plat_args.atari.nat_feat.nf_page;
334 
335 	// probe for ST-MFP
336 	if (m68k_is_hw_register_readable(MFP0_BASE)) {
337 		fMFP[0] = new(sMFP0Buffer) M68KAtari::MFP(MFP0_BASE, MFP0_VECTOR_BASE);
338 	} else
339 		// won't really work anyway from here
340 		panic("You MUST have an ST MFP! Wait, is that *really* an Atari ???");
341 
342 	return B_OK;
343 }
344 
345 
346 status_t
347 M68KAtari::InitSerialDebug(struct kernel_args *kernelArgs)
348 {
349 	nfDebugPrintfID =
350 		kernelArgs->arch_args.plat_args.atari.nat_feat.nf_dprintf_id;
351 
352 #warning M68K: add real serial debug output someday
353 
354 	//out8(0x11, IKBD_BASE+IKBD_DATA);
355 
356 	// now we can expect to see something
357 	ProbeHardware(kernelArgs);
358 
359 	return B_OK;
360 }
361 
362 
363 status_t
364 M68KAtari::InitPostVM(struct kernel_args *kernelArgs)
365 {
366 #if 0
367 	add_debugger_command("of_exit", &debug_command_of_exit,
368 		"Exit to the Open Firmware prompt. No way to get back into the OS!");
369 	add_debugger_command("of_enter", &debug_command_of_enter,
370 		"Enter a subordinate Open Firmware interpreter. Quitting it returns "
371 		"to KDL.");
372 #endif
373 	return B_NO_INIT;
374 	return B_OK;
375 }
376 
377 
378 status_t
379 M68KAtari::InitPIC(struct kernel_args *kernelArgs)
380 {
381 	return B_OK;
382 }
383 
384 
385 status_t
386 M68KAtari::InitRTC(struct kernel_args *kernelArgs,
387 	struct real_time_data *data)
388 {
389 	// XXX we should do this in the bootloader maybe...
390 	kernelArgs->arch_args.time_base_frequency = MFP_SYSTEM_TIME_RATE;
391 	return B_OK;
392 }
393 
394 
395 status_t
396 M68KAtari::InitTimer(struct kernel_args *kernelArgs)
397 {
398 
399 	fMFP[0]->WriteReg(MFP_TACR, 0); // stop it
400 	install_io_interrupt_handler(fMFP[0]->Vector()+13, &MFPTimerInterrupt, this, 0);
401 	return B_OK;
402 }
403 
404 
405 char
406 M68KAtari::BlueScreenGetChar()
407 {
408 	/* polling the keyboard, similar to code in keyboard
409 	 * driver, but without using an interrupt
410 	 * taken almost straight from x86 code
411 	 * XXX: maybe use the keymap from the _AKP cookie instead ?
412 	 */
413 	static bool shiftPressed = false;
414 	static bool controlPressed = false;
415 	static bool altPressed = false;
416 	static uint8 special = 0;
417 	static uint8 special2 = 0;
418 	uint8 key = 0;
419 
420 	if (special & 0x80) {
421 		special &= ~0x80;
422 		return '[';
423 	}
424 	if (special != 0) {
425 		key = special;
426 		special = 0;
427 		return key;
428 	}
429 	if (special2 != 0) {
430 		key = special2;
431 		special2 = 0;
432 		return key;
433 	}
434 
435 	while (true) {
436 		uint8 status = in8(IKBD_BASE+IKBD_CTRL);
437 
438 		if ((status & IKBD_STATUS_READ_BUFFER_FULL) == 0) {
439 			// no data in keyboard buffer
440 			spin(200);
441 			//kprintf("no key\n");
442 			continue;
443 		}
444 
445 		spin(200);
446 		key = in8(IKBD_BASE+IKBD_DATA);
447 		/*
448 		kprintf("key: %02x, %sshift %scontrol %salt\n",
449 			key,
450 			shiftPressed?"":"!",
451 			controlPressed?"":"!",
452 			altPressed?"":"!");
453 		*/
454 
455 		if (key & 0x80) {
456 			// key up
457 			switch (key & ~0x80) {
458 				case LEFT_SHIFT:
459 				case RIGHT_SHIFT:
460 					shiftPressed = false;
461 					break;
462 				case LEFT_CONTROL:
463 					controlPressed = false;
464 					break;
465 				case LEFT_ALT:
466 					altPressed = false;
467 					break;
468 			}
469 		} else {
470 			// key down
471 			switch (key) {
472 				case LEFT_SHIFT:
473 				case RIGHT_SHIFT:
474 					shiftPressed = true;
475 					break;
476 
477 				case LEFT_CONTROL:
478 					controlPressed = true;
479 					break;
480 
481 				case LEFT_ALT:
482 					altPressed = true;
483 					break;
484 
485 				// start escape sequence for cursor movement
486 				case CURSOR_UP:
487 					special = 0x80 | 'A';
488 					return '\x1b';
489 				case CURSOR_DOWN:
490 					special = 0x80 | 'B';
491 					return '\x1b';
492 				case CURSOR_RIGHT:
493 					special = 0x80 | 'C';
494 					return '\x1b';
495 				case CURSOR_LEFT:
496 					special = 0x80 | 'D';
497 					return '\x1b';
498 				case CURSOR_HOME:
499 					special = 0x80 | 'H';
500 					return '\x1b';
501 				case CURSOR_END:
502 					special = 0x80 | 'F';
503 					return '\x1b';
504 				case PAGE_UP:
505 					special = 0x80 | '5';
506 					special2 = '~';
507 					return '\x1b';
508 				case PAGE_DOWN:
509 					special = 0x80 | '6';
510 					special2 = '~';
511 					return '\x1b';
512 
513 
514 				case DELETE:
515 					if (controlPressed && altPressed)
516 						arch_cpu_shutdown(true);
517 
518 					special = 0x80 | '3';
519 					special2 = '~';
520 					return '\x1b';
521 
522 				default:
523 					if (controlPressed) {
524 						char c = kShiftedKeymap[key];
525 						if (c >= 'A' && c <= 'Z')
526 							return 0x1f & c;
527 					}
528 
529 					if (altPressed)
530 						return kAltedKeymap[key];
531 
532 					return shiftPressed
533 						? kShiftedKeymap[key] : kUnshiftedKeymap[key];
534 			}
535 		}
536 	}
537 }
538 
539 
540 char
541 M68KAtari::SerialDebugGetChar()
542 {
543 	//WRITEME
544 	return BlueScreenGetChar();
545 	//return 0;
546 }
547 
548 
549 void
550 M68KAtari::SerialDebugPutChar(char c)
551 {
552 	if (nfCall && nfDebugPrintfID) {
553 #if 0
554 		static char buffer[2] = { '\0', '\0' };
555 		buffer[0] = c;
556 
557 		nfCall(nfDebugPrintfID /*| 0*/, buffer);
558 #endif
559 		nfPage[0] = c;
560 		nfPage[1] = '\0';
561 		nfCall(nfDebugPrintfID /*| 0*/, nfPage);
562 	}
563 
564 #warning M68K: WRITEME
565 	// real serial
566 	//panic("WRITEME");
567 }
568 
569 
570 void
571 M68KAtari::EnableIOInterrupt(int32 irq)
572 {
573 	MFP *mfp = MFPForIrq(irq);
574 
575 	if (mfp)
576 		mfp->EnableIOInterrupt(irq - mfp->Vector());
577 }
578 
579 
580 void
581 M68KAtari::DisableIOInterrupt(int32 irq)
582 {
583 	MFP *mfp = MFPForIrq(irq);
584 
585 	if (mfp)
586 		mfp->DisableIOInterrupt(irq - mfp->Vector());
587 }
588 
589 
590 bool
591 M68KAtari::AcknowledgeIOInterrupt(int32 irq)
592 {
593 	MFP *mfp = MFPForIrq(irq);
594 
595 	if (mfp)
596 		return mfp->AcknowledgeIOInterrupt(irq - mfp->Vector());
597 	return false;
598 }
599 
600 
601 uint8
602 M68KAtari::ReadRTCReg(uint8 reg)
603 {
604 	// fake century
605 	// (on MC146818A it's in the RAM, but probably it's used for that purpose...)
606 	// but just in case, we're in 20xx now anyway :)
607 	if (reg == 0x32)
608 		return 0x20;
609 	return fRTC->ReadReg(reg);
610 }
611 
612 
613 void
614 M68KAtari::WriteRTCReg(uint8 reg, uint8 val)
615 {
616 	fRTC->WriteReg(reg, val);
617 }
618 
619 void
620 M68KAtari::SetHardwareRTC(uint32 seconds)
621 {
622 #warning M68K: WRITEME
623 }
624 
625 
626 uint32
627 M68KAtari::GetHardwareRTC()
628 {
629 #warning M68K: WRITEME
630 	return 0;
631 }
632 
633 
634 void
635 M68KAtari::SetHardwareTimer(bigtime_t timeout)
636 {
637 	uint8 nextEventClocks;
638 	if (timeout <= 0)
639 		nextEventClocks = 2;
640 	else if (timeout < MFP_MAX_TIMER_INTERVAL)
641 		nextEventClocks = timeout * MFP_TIMER_RATE / 1000000;
642 	else
643 		nextEventClocks = 0xff;
644 
645 	fMFP[0]->WriteReg(SYS_TDR, nextEventClocks);
646 	// delay mode, device by 4
647 	fMFP[0]->WriteReg(SYS_TCR, (fMFP[0]->ReadReg(SYS_TCR) & SYS_TCRMASK) | SYS_TENABLE);
648 	// enable irq
649 	EnableIOInterrupt(MFP1_VECTOR_BASE + SYS_TVECTOR);
650 }
651 
652 
653 void
654 M68KAtari::ClearHardwareTimer(void)
655 {
656 	// disable the irq (as on PC but I'm not sure it's needed)
657 	DisableIOInterrupt(MFP1_VECTOR_BASE + SYS_TVECTOR);
658 	// stop it, we don't want another countdown
659 	fMFP[0]->WriteReg(SYS_TCR, (fMFP[0]->ReadReg(SYS_TCR) & SYS_TCRMASK) | SYS_TDISABLE);
660 }
661 
662 
663 void
664 M68KAtari::ShutDown(bool reboot)
665 {
666 	panic("Bombs!");
667 	panic("WRITEME");
668 }
669 
670 
671 M68KAtari::MFP *
672 M68KAtari::MFPForIrq(int irq)
673 {
674 	int i;
675 
676 	for (i = 0; i < 2; i++) {
677 		if (fMFP[i]) {
678 			if (irq >= fMFP[i]->Vector() && irq < fMFP[i]->Vector() + 16)
679 				return fMFP[i];
680 		}
681 	}
682 	return NULL;
683 }
684 
685 int32
686 M68KAtari::MFPTimerInterrupt(void *data)
687 {
688 	M68KAtari *_this = (M68KAtari *)data;
689 	// disable the timer, else it will loop again with the same value
690 	_this->ClearHardwareTimer();
691 	// handle the timer
692 	return timer_interrupt();
693 }
694 
695 
696 // static buffer for constructing the actual M68KPlatform
697 static char *sM68KPlatformBuffer[sizeof(M68KAtari)];
698 #warning PTR HERE ???
699 
700 
701 M68KPlatform *instanciate_m68k_platform_atari()
702 {
703 	return new(sM68KPlatformBuffer) M68KAtari;
704 }
705