Atari kernel platform code.
*/
#include <arch_platform.h>
#include <new>
#include <util/kernel_cpp.h>
#include <KernelExport.h>
#include <boot/kernel_args.h>
#include <arch/cpu.h>
#include <platform/atari_m68k/MFP.h>
#include <platform/atari_m68k/platform_atari_m68k.h>
#include <real_time_clock.h>
#include <timer.h>
#include "debugger_keymaps.h"
#define SYS_TDR MFP_TADR
#define SYS_TCR MFP_TACR
#define SYS_TCRMASK 0x0f /* mask for timer control (0xf for A&B, 0x7 for C, 0x38 for D) */
#define SYS_TENABLE 0x01 /* delay mode with /4 prescaler: 0x01 (<<3 for timer D) */
#define SYS_TDISABLE 0x00
#define SYS_TVECTOR 13
#define MFP_PRESCALER 4
#define MFP_TIMER_RATE (MFP_FREQ/MFP_PRESCALER)
#define MFP_MAX_TIMER_INTERVAL (0xff * 1000000L / MFP_TIMER_RATE)
#define MFP_SYSTEM_TIME_RATE (MFP_FREQ/MFP_PRESCALER)
#define MFP0_BASE 0xFFFFFA00
#define MFP1_BASE 0xFFFFFA80
#define MFP0_VECTOR_BASE 64
#define MFP1_VECTOR_BASE (MFP0_VECTOR_BASE+16)
#define TT_RTC_BASE 0xFFFF8960
#define TT_RTC_VECTOR (MFP1_VECTOR_BASE+14)
#define SCC_C0_VECTOR_BASE (MFP1_VECTOR_BASE+16)
#define SCC_C1_VECTOR_BASE (0x1BC/4)
#define IKBD_BASE 0xFFFFFC00
#define IKBD_CTRL 0
#define IKBD_DATA 2
#define IKBD_STATUS_READ_BUFFER_FULL 0x01
enum keycodes {
LEFT_SHIFT = 42,
RIGHT_SHIFT = 54,
LEFT_CONTROL = 29,
LEFT_ALT = 56,
CURSOR_LEFT = 75,
CURSOR_RIGHT = 77,
CURSOR_UP = 72,
CURSOR_DOWN = 80,
CURSOR_HOME = 71,
CURSOR_END = 79,
PAGE_UP = 73,
PAGE_DOWN = 81,
DELETE = 83,
F12 = 88,
};
#define in8(a) (*(volatile uint8 *)(a))
#define out8(v, a) (*(volatile uint8 *)(a) = v)
namespace BPrivate {
class M68KAtari : public M68KPlatform {
public:
class MFP {
public:
MFP(uint32 base, int vector);
~MFP();
uint32 Base() const { return fBase; };
int Vector() const { return fVector; };
uint8 ReadReg(uint32 reg) { return in8(fBase + reg); };
void WriteReg(uint32 reg, uint8 v) { out8(v, fBase + reg); };
void EnableIOInterrupt(int32 irq);
void DisableIOInterrupt(int32 irq);
bool AcknowledgeIOInterrupt(int32 irq);
private:
uint32 fBase;
int fVector;
};
class RTC {
public:
RTC(uint32 base, int vector);
~RTC();
uint32 Base() const { return fBase; };
int Vector() const { return fVector; };
uint8 ReadReg(uint32 reg);
void WriteReg(uint32 reg, uint8 v) { out8((uint8)reg,fBase+1); out8(v,fBase+3); };
private:
uint32 fBase;
int fVector;
};
M68KAtari();
virtual ~M68KAtari();
void ProbeHardware(struct kernel_args *kernelArgs);
virtual status_t Init(struct kernel_args *kernelArgs);
virtual status_t InitSerialDebug(struct kernel_args *kernelArgs);
virtual status_t InitPostVM(struct kernel_args *kernelArgs);
virtual status_t InitPIC(struct kernel_args *kernelArgs);
virtual status_t InitRTC(struct kernel_args *kernelArgs,
struct real_time_data *data);
virtual status_t InitTimer(struct kernel_args *kernelArgs);
virtual char BlueScreenGetChar();
virtual char SerialDebugGetChar();
virtual void SerialDebugPutChar(char c);
virtual void EnableIOInterrupt(int32 irq);
virtual void DisableIOInterrupt(int32 irq);
virtual bool AcknowledgeIOInterrupt(int32 irq);
virtual uint8 ReadRTCReg(uint8 reg);
virtual void WriteRTCReg(uint8 reg, uint8 val);
virtual void SetHardwareRTC(uint32 seconds);
virtual uint32 GetHardwareRTC();
virtual void SetHardwareTimer(bigtime_t timeout);
virtual void ClearHardwareTimer(void);
virtual void ShutDown(bool reboot);
private:
MFP *MFPForIrq(int irq);
static int32 MFPTimerInterrupt(void *data);
MFP *fMFP[2];
RTC *fRTC;
uint32 (*nfGetID)(const char *name);
int32 (*nfCall)(uint32 ID, ...);
char *nfPage;
uint32 nfDebugPrintfID;
};
}
using BPrivate::M68KAtari;
static char sMFP0Buffer[sizeof(M68KAtari::MFP)];
static char sMFP1Buffer[sizeof(M68KAtari::MFP)];
M68KAtari::MFP::MFP(uint32 base, int vector)
{
fBase = base;
fVector = vector;
}
M68KAtari::MFP::~MFP()
{
}
#warning M68K: use enable or mark register ?
void
M68KAtari::MFP::EnableIOInterrupt(int irq)
{
uint8 bit = 1 << (irq % 8);
uint32 reg = Base() + ((irq > 8) ? (MFP_IERA) : (MFP_IERB));
uint8 val = in8(reg);
if (val & bit == 0) {
val |= bit;
out8(val, reg);
}
}
void
M68KAtari::MFP::DisableIOInterrupt(int irq)
{
uint8 bit = 1 << (irq % 8);
uint32 reg = Base() + ((irq > 8) ? (MFP_IERA) : (MFP_IERB));
uint8 val = in8(reg);
if (val & bit) {
val &= ~bit;
out8(val, reg);
}
}
bool
M68KAtari::MFP::AcknowledgeIOInterrupt(int irq)
{
uint8 bit = 1 << (irq % 8);
uint32 reg = Base() + ((irq > 8) ? (MFP_ISRA) : (MFP_ISRB));
uint8 val = in8(reg);
if (val & bit) {
val &= ~bit;
out8(val, reg);
return true;
}
return false;
}
static char sRTCBuffer[sizeof(M68KAtari::RTC)];
M68KAtari::RTC::RTC(uint32 base, int vector)
{
fBase = base;
fVector = vector;
}
M68KAtari::RTC::~RTC()
{
}
uint8
M68KAtari::RTC::ReadReg(uint32 reg)
{
int waitTime = 10000;
if (reg < 0x0a) {
out8(0x0a, fBase+1);
while((in8(fBase+3) & 0x80) && --waitTime);
}
out8((uint8)reg,fBase+1);
return in8(fBase+3);
}
M68KAtari::M68KAtari()
: M68KPlatform(M68K_PLATFORM_ATARI)
{
}
M68KAtari::~M68KAtari()
{
}
void
M68KAtari::ProbeHardware(struct kernel_args *kernelArgs)
{
dprintf("Atari hardware:\n");
dprintf(" ST MFP\n");
if (m68k_is_hw_register_readable(MFP1_BASE)) {
dprintf(" TT MFP\n");
fMFP[1] = new(sMFP1Buffer) M68KAtari::MFP(MFP1_BASE, MFP1_VECTOR_BASE);
}
if (m68k_is_hw_register_readable(TT_RTC_BASE)) {
dprintf(" TT RTC MC146818A\n");
fRTC = new(sRTCBuffer) M68KAtari::RTC(TT_RTC_BASE,TT_RTC_VECTOR);
} else
panic("TT RTC required!");
}
status_t
M68KAtari::Init(struct kernel_args *kernelArgs)
{
fMFP[0] = NULL;
fMFP[1] = NULL;
fRTC = NULL;
nfGetID =
kernelArgs->arch_args.plat_args.atari.nat_feat.nf_get_id;
nfCall =
kernelArgs->arch_args.plat_args.atari.nat_feat.nf_call;
nfPage = (char *)
kernelArgs->arch_args.plat_args.atari.nat_feat.nf_page;
if (m68k_is_hw_register_readable(MFP0_BASE)) {
fMFP[0] = new(sMFP0Buffer) M68KAtari::MFP(MFP0_BASE, MFP0_VECTOR_BASE);
} else
panic("You MUST have an ST MFP! Wait, is that *really* an Atari ???");
return B_OK;
}
status_t
M68KAtari::InitSerialDebug(struct kernel_args *kernelArgs)
{
nfDebugPrintfID =
kernelArgs->arch_args.plat_args.atari.nat_feat.nf_dprintf_id;
#warning M68K: add real serial debug output someday
ProbeHardware(kernelArgs);
return B_OK;
}
status_t
M68KAtari::InitPostVM(struct kernel_args *kernelArgs)
{
#if 0
add_debugger_command("of_exit", &debug_command_of_exit,
"Exit to the Open Firmware prompt. No way to get back into the OS!");
add_debugger_command("of_enter", &debug_command_of_enter,
"Enter a subordinate Open Firmware interpreter. Quitting it returns "
"to KDL.");
#endif
return B_NO_INIT;
return B_OK;
}
status_t
M68KAtari::InitPIC(struct kernel_args *kernelArgs)
{
return B_OK;
}
status_t
M68KAtari::InitRTC(struct kernel_args *kernelArgs,
struct real_time_data *data)
{
kernelArgs->arch_args.time_base_frequency = MFP_SYSTEM_TIME_RATE;
return B_OK;
}
status_t
M68KAtari::InitTimer(struct kernel_args *kernelArgs)
{
fMFP[0]->WriteReg(MFP_TACR, 0);
install_io_interrupt_handler(fMFP[0]->Vector()+13, &MFPTimerInterrupt, this, 0);
return B_OK;
}
char
M68KAtari::BlueScreenGetChar()
{
* driver, but without using an interrupt
* taken almost straight from x86 code
* XXX: maybe use the keymap from the _AKP cookie instead ?
*/
static bool shiftPressed = false;
static bool controlPressed = false;
static bool altPressed = false;
static uint8 special = 0;
static uint8 special2 = 0;
uint8 key = 0;
if (special & 0x80) {
special &= ~0x80;
return '[';
}
if (special != 0) {
key = special;
special = 0;
return key;
}
if (special2 != 0) {
key = special2;
special2 = 0;
return key;
}
while (true) {
uint8 status = in8(IKBD_BASE+IKBD_CTRL);
if ((status & IKBD_STATUS_READ_BUFFER_FULL) == 0) {
spin(200);
continue;
}
spin(200);
key = in8(IKBD_BASE+IKBD_DATA);
kprintf("key: %02x, %sshift %scontrol %salt\n",
key,
shiftPressed?"":"!",
controlPressed?"":"!",
altPressed?"":"!");
*/
if (key & 0x80) {
switch (key & ~0x80) {
case LEFT_SHIFT:
case RIGHT_SHIFT:
shiftPressed = false;
break;
case LEFT_CONTROL:
controlPressed = false;
break;
case LEFT_ALT:
altPressed = false;
break;
}
} else {
switch (key) {
case LEFT_SHIFT:
case RIGHT_SHIFT:
shiftPressed = true;
break;
case LEFT_CONTROL:
controlPressed = true;
break;
case LEFT_ALT:
altPressed = true;
break;
case CURSOR_UP:
special = 0x80 | 'A';
return '\x1b';
case CURSOR_DOWN:
special = 0x80 | 'B';
return '\x1b';
case CURSOR_RIGHT:
special = 0x80 | 'C';
return '\x1b';
case CURSOR_LEFT:
special = 0x80 | 'D';
return '\x1b';
case CURSOR_HOME:
special = 0x80 | 'H';
return '\x1b';
case CURSOR_END:
special = 0x80 | 'F';
return '\x1b';
case PAGE_UP:
special = 0x80 | '5';
special2 = '~';
return '\x1b';
case PAGE_DOWN:
special = 0x80 | '6';
special2 = '~';
return '\x1b';
case DELETE:
if (controlPressed && altPressed)
arch_cpu_shutdown(true);
special = 0x80 | '3';
special2 = '~';
return '\x1b';
default:
if (controlPressed) {
char c = kShiftedKeymap[key];
if (c >= 'A' && c <= 'Z')
return 0x1f & c;
}
if (altPressed)
return kAltedKeymap[key];
return shiftPressed
? kShiftedKeymap[key] : kUnshiftedKeymap[key];
}
}
}
}
char
M68KAtari::SerialDebugGetChar()
{
return BlueScreenGetChar();
}
void
M68KAtari::SerialDebugPutChar(char c)
{
if (nfCall && nfDebugPrintfID) {
#if 0
static char buffer[2] = { '\0', '\0' };
buffer[0] = c;
nfCall(nfDebugPrintfID , buffer);
#endif
nfPage[0] = c;
nfPage[1] = '\0';
nfCall(nfDebugPrintfID , nfPage);
}
#warning M68K: WRITEME
}
void
M68KAtari::EnableIOInterrupt(int32 irq)
{
MFP *mfp = MFPForIrq(irq);
if (mfp)
mfp->EnableIOInterrupt(irq - mfp->Vector());
}
void
M68KAtari::DisableIOInterrupt(int32 irq)
{
MFP *mfp = MFPForIrq(irq);
if (mfp)
mfp->DisableIOInterrupt(irq - mfp->Vector());
}
bool
M68KAtari::AcknowledgeIOInterrupt(int32 irq)
{
MFP *mfp = MFPForIrq(irq);
if (mfp)
return mfp->AcknowledgeIOInterrupt(irq - mfp->Vector());
return false;
}
uint8
M68KAtari::ReadRTCReg(uint8 reg)
{
if (reg == 0x32)
return 0x20;
return fRTC->ReadReg(reg);
}
void
M68KAtari::WriteRTCReg(uint8 reg, uint8 val)
{
fRTC->WriteReg(reg, val);
}
void
M68KAtari::SetHardwareRTC(uint32 seconds)
{
#warning M68K: WRITEME
}
uint32
M68KAtari::GetHardwareRTC()
{
#warning M68K: WRITEME
return 0;
}
void
M68KAtari::SetHardwareTimer(bigtime_t timeout)
{
uint8 nextEventClocks;
if (timeout <= 0)
nextEventClocks = 2;
else if (timeout < MFP_MAX_TIMER_INTERVAL)
nextEventClocks = timeout * MFP_TIMER_RATE / 1000000;
else
nextEventClocks = 0xff;
fMFP[0]->WriteReg(SYS_TDR, nextEventClocks);
fMFP[0]->WriteReg(SYS_TCR, (fMFP[0]->ReadReg(SYS_TCR) & SYS_TCRMASK) | SYS_TENABLE);
EnableIOInterrupt(MFP1_VECTOR_BASE + SYS_TVECTOR);
}
void
M68KAtari::ClearHardwareTimer(void)
{
DisableIOInterrupt(MFP1_VECTOR_BASE + SYS_TVECTOR);
fMFP[0]->WriteReg(SYS_TCR, (fMFP[0]->ReadReg(SYS_TCR) & SYS_TCRMASK) | SYS_TDISABLE);
}
void
M68KAtari::ShutDown(bool reboot)
{
panic("Bombs!");
panic("WRITEME");
}
M68KAtari::MFP *
M68KAtari::MFPForIrq(int irq)
{
int i;
for (i = 0; i < 2; i++) {
if (fMFP[i]) {
if (irq >= fMFP[i]->Vector() && irq < fMFP[i]->Vector() + 16)
return fMFP[i];
}
}
return NULL;
}
int32
M68KAtari::MFPTimerInterrupt(void *data)
{
M68KAtari *_this = (M68KAtari *)data;
_this->ClearHardwareTimer();
return timer_interrupt();
}
static char *sM68KPlatformBuffer[sizeof(M68KAtari)];
#warning PTR HERE ???
M68KPlatform *instanciate_m68k_platform_atari()
{
return new(sM68KPlatformBuffer) M68KAtari;
}