upstream u-boot with additional patches for our devices/boards:
https://lists.denx.de/pipermail/u-boot/2017-March/282789.html (AXP crashes) ;
Gbit ethernet patch for some LIME2 revisions ;
with SPI flash support
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
814 lines
16 KiB
814 lines
16 KiB
#include "x86emu.h"
|
|
#include "glue.h"
|
|
|
|
|
|
/*
|
|
* This isn't nice, but there are a lot of incompatibilities in the U-Boot and scitech include
|
|
* files that this is the only really workable solution.
|
|
* Might be cleaned out later.
|
|
*/
|
|
|
|
#ifdef DEBUG
|
|
#undef DEBUG
|
|
#endif
|
|
|
|
#undef IO_LOGGING
|
|
#undef MEM_LOGGING
|
|
|
|
#ifdef IO_LOGGING
|
|
#define LOGIO(port, format, args...) if (dolog(port)) _printf(format , ## args)
|
|
#else
|
|
#define LOGIO(port, format, args...)
|
|
#endif
|
|
|
|
#ifdef MEM_LOGGIN
|
|
#define LOGMEM(format, args...) _printf(format , ## args)
|
|
#else
|
|
#define LOGMEM(format, args...)
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#define PRINTF(format, args...) _printf(format , ## args)
|
|
#else
|
|
#define PRINTF(format, argc...)
|
|
#endif
|
|
|
|
typedef unsigned char UBYTE;
|
|
typedef unsigned short UWORD;
|
|
typedef unsigned long ULONG;
|
|
|
|
typedef char BYTE;
|
|
typedef short WORT;
|
|
typedef long LONG;
|
|
|
|
#define EMULATOR_MEM_SIZE (1024*1024)
|
|
#define EMULATOR_BIOS_OFFSET 0xC0000
|
|
#define EMULATOR_STRAP_OFFSET 0x30000
|
|
#define EMULATOR_STACK_OFFSET 0x20000
|
|
#define EMULATOR_LOGO_OFFSET 0x40000 // If you change this, change the strap code, too
|
|
#define VIDEO_BASE (void *)0xFD0B8000
|
|
|
|
extern char *getenv(char *);
|
|
extern int tstc(void);
|
|
extern int getc(void);
|
|
extern unsigned char video_get_attr(void);
|
|
|
|
int atoi(char *string)
|
|
{
|
|
int res = 0;
|
|
while (*string>='0' && *string <='9')
|
|
{
|
|
res *= 10;
|
|
res += *string-'0';
|
|
string++;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void cons_gets(char *buffer)
|
|
{
|
|
int i = 0;
|
|
char c = 0;
|
|
|
|
buffer[0] = 0;
|
|
if (getenv("x86_runthru")) return; //FIXME:
|
|
while (c != 0x0D && c != 0x0A)
|
|
{
|
|
while (!tstc());
|
|
c = getc();
|
|
if (c>=32 && c < 127)
|
|
{
|
|
buffer[i] = c;
|
|
i++;
|
|
buffer[i] = 0;
|
|
putc(c);
|
|
}
|
|
else
|
|
{
|
|
if (c == 0x08)
|
|
{
|
|
if (i>0) i--;
|
|
buffer[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
buffer[i] = '\n';
|
|
buffer[i+1] = 0;
|
|
}
|
|
|
|
char *bios_date = "08/14/02";
|
|
UBYTE model = 0xFC;
|
|
UBYTE submodel = 0x00;
|
|
|
|
static inline UBYTE read_byte(volatile UBYTE* from)
|
|
{
|
|
int x;
|
|
asm volatile ("lbz %0,%1\n eieio" : "=r" (x) : "m" (*from));
|
|
return (UBYTE)x;
|
|
}
|
|
|
|
static inline void write_byte(volatile UBYTE *to, int x)
|
|
{
|
|
asm volatile ("stb %1,%0\n eieio" : "=m" (*to) : "r" (x));
|
|
}
|
|
|
|
static inline UWORD read_word_little(volatile UWORD *from)
|
|
{
|
|
int x;
|
|
asm volatile ("lhbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m" (*from));
|
|
return (UWORD)x;
|
|
}
|
|
|
|
static inline UWORD read_word_big(volatile UWORD *from)
|
|
{
|
|
int x;
|
|
asm volatile ("lhz %0,%1\n eieio" : "=r" (x) : "m" (*from));
|
|
return (UWORD)x;
|
|
}
|
|
|
|
static inline void write_word_little(volatile UWORD *to, int x)
|
|
{
|
|
asm volatile ("sthbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
|
|
}
|
|
|
|
static inline void write_word_big(volatile UWORD *to, int x)
|
|
{
|
|
asm volatile ("sth %1,%0\n eieio" : "=m" (*to) : "r" (x));
|
|
}
|
|
|
|
static inline ULONG read_long_little(volatile ULONG *from)
|
|
{
|
|
unsigned long x;
|
|
asm volatile ("lwbrx %0,0,%1\n eieio" : "=r" (x) : "r" (from), "m"(*from));
|
|
return (ULONG)x;
|
|
}
|
|
|
|
static inline ULONG read_long_big(volatile ULONG *from)
|
|
{
|
|
unsigned long x;
|
|
asm volatile ("lwz %0,%1\n eieio" : "=r" (x) : "m" (*from));
|
|
return (ULONG)x;
|
|
}
|
|
|
|
static inline void write_long_little(volatile ULONG *to, ULONG x)
|
|
{
|
|
asm volatile ("stwbrx %1,0,%2\n eieio" : "=m" (*to) : "r" (x), "r" (to));
|
|
}
|
|
|
|
static inline void write_long_big(volatile ULONG *to, ULONG x)
|
|
{
|
|
asm volatile ("stw %1,%0\n eieio" : "=m" (*to) : "r" (x));
|
|
}
|
|
|
|
static int log_init = 0;
|
|
static int log_do = 0;
|
|
static int log_low = 0;
|
|
|
|
int dolog(int port)
|
|
{
|
|
if (log_init && log_do)
|
|
{
|
|
if (log_low && port > 0x400) return 0;
|
|
return 1;
|
|
}
|
|
|
|
if (!log_init)
|
|
{
|
|
log_init = 1;
|
|
log_do = (getenv("x86_logio") != (char *)0);
|
|
log_low = (getenv("x86_loglow") != (char *)0);
|
|
if (log_do)
|
|
{
|
|
if (log_low && port > 0x400) return 0;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Converts an emulator address to a physical address.
|
|
// Handles all special cases (bios date, model etc), and might need work
|
|
u32 memaddr(u32 addr)
|
|
{
|
|
// if (addr >= 0xF0000 && addr < 0xFFFFF) printf("WARNING: Segment F access (0x%x)\n", addr);
|
|
// printf("MemAddr=%p\n", addr);
|
|
if (addr >= 0xA0000 && addr < 0xC0000)
|
|
return 0xFD000000 + addr;
|
|
else if (addr >= 0xFFFF5 && addr < 0xFFFFE)
|
|
{
|
|
return (u32)bios_date+addr-0xFFFF5;
|
|
}
|
|
else if (addr == 0xFFFFE)
|
|
return (u32)&model;
|
|
else if (addr == 0xFFFFF)
|
|
return (u32)&submodel;
|
|
else if (addr >= 0x80000000)
|
|
{
|
|
//printf("Warning: High memory access at 0x%x\n", addr);
|
|
return addr;
|
|
}
|
|
else
|
|
return (u32)M.mem_base+addr;
|
|
}
|
|
|
|
u8 A1_rdb(u32 addr)
|
|
{
|
|
u8 a = read_byte((UBYTE *)memaddr(addr));
|
|
LOGMEM("rdb: %x -> %x\n", addr, a);
|
|
return a;
|
|
}
|
|
|
|
u16 A1_rdw(u32 addr)
|
|
{
|
|
u16 a = read_word_little((UWORD *)memaddr(addr));
|
|
LOGMEM("rdw: %x -> %x\n", addr, a);
|
|
return a;
|
|
}
|
|
|
|
u32 A1_rdl(u32 addr)
|
|
{
|
|
u32 a = read_long_little((ULONG *)memaddr(addr));
|
|
LOGMEM("rdl: %x -> %x\n", addr, a);
|
|
return a;
|
|
}
|
|
|
|
void A1_wrb(u32 addr, u8 val)
|
|
{
|
|
LOGMEM("wrb: %x <- %x\n", addr, val);
|
|
write_byte((UBYTE *)memaddr(addr), val);
|
|
}
|
|
|
|
void A1_wrw(u32 addr, u16 val)
|
|
{
|
|
LOGMEM("wrw: %x <- %x\n", addr, val);
|
|
write_word_little((UWORD *)memaddr(addr), val);
|
|
}
|
|
|
|
void A1_wrl(u32 addr, u32 val)
|
|
{
|
|
LOGMEM("wrl: %x <- %x\n", addr, val);
|
|
write_long_little((ULONG *)memaddr(addr), val);
|
|
}
|
|
|
|
X86EMU_memFuncs _A1_mem =
|
|
{
|
|
A1_rdb,
|
|
A1_rdw,
|
|
A1_rdl,
|
|
A1_wrb,
|
|
A1_wrw,
|
|
A1_wrl,
|
|
};
|
|
|
|
#define ARTICIAS_PCI_CFGADDR 0xfec00cf8
|
|
#define ARTICIAS_PCI_CFGDATA 0xfee00cfc
|
|
#define IOBASE 0xFE000000
|
|
|
|
#define in_byte(from) read_byte( (UBYTE *)port_to_mem(from))
|
|
#define in_word(from) read_word_little((UWORD *)port_to_mem(from))
|
|
#define in_long(from) read_long_little((ULONG *)port_to_mem(from))
|
|
#define out_byte(to, val) write_byte((UBYTE *)port_to_mem(to), val)
|
|
#define out_word(to, val) write_word_little((UWORD *)port_to_mem(to), val)
|
|
#define out_long(to, val) write_long_little((ULONG *)port_to_mem(to), val)
|
|
|
|
u32 port_to_mem(int port)
|
|
{
|
|
if (port >= 0xCFC && port <= 0xCFF) return 0xFEE00000+port;
|
|
else if (port >= 0xCF8 && port <= 0xCFB) return 0xFEC00000+port;
|
|
else return IOBASE + port;
|
|
}
|
|
|
|
u8 A1_inb(int port)
|
|
{
|
|
u8 a;
|
|
//if (port == 0x3BA) return 0;
|
|
a = in_byte(port);
|
|
LOGIO(port, "inb: %Xh -> %d (%Xh)\n", port, a, a);
|
|
return a;
|
|
}
|
|
|
|
u16 A1_inw(int port)
|
|
{
|
|
u16 a = in_word(port);
|
|
LOGIO(port, "inw: %Xh -> %d (%Xh)\n", port, a, a);
|
|
return a;
|
|
}
|
|
|
|
u32 A1_inl(int port)
|
|
{
|
|
u32 a = in_long(port);
|
|
LOGIO(port, "inl: %Xh -> %d (%Xh)\n", port, a, a);
|
|
return a;
|
|
}
|
|
|
|
void A1_outb(int port, u8 val)
|
|
{
|
|
LOGIO(port, "outb: %Xh <- %d (%Xh)\n", port, val, val);
|
|
/* if (port == 0xCF8) port = 0xCFB;
|
|
else if (port == 0xCF9) port = 0xCFA;
|
|
else if (port == 0xCFA) port = 0xCF9;
|
|
else if (port == 0xCFB) port = 0xCF8;*/
|
|
out_byte(port, val);
|
|
}
|
|
|
|
void A1_outw(int port, u16 val)
|
|
{
|
|
LOGIO(port, "outw: %Xh <- %d (%Xh)\n", port, val, val);
|
|
out_word(port, val);
|
|
}
|
|
|
|
void A1_outl(int port, u32 val)
|
|
{
|
|
LOGIO(port, "outl: %Xh <- %d (%Xh)\n", port, val, val);
|
|
out_long(port, val);
|
|
}
|
|
|
|
X86EMU_pioFuncs _A1_pio =
|
|
{
|
|
A1_inb,
|
|
A1_inw,
|
|
A1_inl,
|
|
A1_outb,
|
|
A1_outw,
|
|
A1_outl,
|
|
};
|
|
|
|
static int reloced_ops = 0;
|
|
|
|
void reloc_ops(void *reloc_addr)
|
|
{
|
|
extern void (*x86emu_optab[256])(u8);
|
|
extern void (*x86emu_optab2[256])(u8);
|
|
extern void tables_relocate(unsigned int offset);
|
|
int i;
|
|
unsigned long delta;
|
|
if (reloced_ops == 1) return;
|
|
reloced_ops = 1;
|
|
|
|
delta = TEXT_BASE - (unsigned long)reloc_addr;
|
|
|
|
for (i=0; i<256; i++)
|
|
{
|
|
x86emu_optab[i] -= delta;
|
|
x86emu_optab2[i] -= delta;
|
|
}
|
|
|
|
_A1_mem.rdb = A1_rdb;
|
|
_A1_mem.rdw = A1_rdw;
|
|
_A1_mem.rdl = A1_rdl;
|
|
_A1_mem.wrb = A1_wrb;
|
|
_A1_mem.wrw = A1_wrw;
|
|
_A1_mem.wrl = A1_wrl;
|
|
|
|
_A1_pio.inb = A1_inb;
|
|
_A1_pio.inw = A1_inw;
|
|
_A1_pio.inl = A1_inl;
|
|
_A1_pio.outb = A1_outb;
|
|
_A1_pio.outw = A1_outw;
|
|
_A1_pio.outl = A1_outl;
|
|
|
|
tables_relocate(delta);
|
|
|
|
}
|
|
|
|
|
|
#define ANY_KEY(text) \
|
|
printf(text); \
|
|
while (!tstc());
|
|
|
|
|
|
unsigned char more_strap[] = {
|
|
0xb4, 0x0, 0xb0, 0x2, 0xcd, 0x10,
|
|
};
|
|
#define MORE_STRAP_BYTES 6 // Additional bytes of strap code
|
|
|
|
|
|
unsigned char *done_msg="VGA Initialized\0";
|
|
|
|
int execute_bios(pci_dev_t gr_dev, void *reloc_addr)
|
|
{
|
|
extern void bios_init(void);
|
|
extern void remove_init_data(void);
|
|
extern int video_rows(void);
|
|
extern int video_cols(void);
|
|
extern int video_size(int, int);
|
|
u8 *strap;
|
|
unsigned char *logo;
|
|
u8 cfg;
|
|
int i;
|
|
char c;
|
|
char *s;
|
|
#ifdef EASTEREGG
|
|
int easteregg_active = 0;
|
|
#endif
|
|
char *pal_reset;
|
|
u8 *fb;
|
|
unsigned char *msg;
|
|
unsigned char current_attr;
|
|
|
|
PRINTF("Trying to remove init data\n");
|
|
remove_init_data();
|
|
PRINTF("Removed init data from cache, now in RAM\n");
|
|
|
|
reloc_ops(reloc_addr);
|
|
PRINTF("Attempting to run emulator on %02x:%02x:%02x\n",
|
|
PCI_BUS(gr_dev), PCI_DEV(gr_dev), PCI_FUNC(gr_dev));
|
|
|
|
// Enable compatibility hole for emulator access to frame buffer
|
|
PRINTF("Enabling compatibility hole\n");
|
|
enable_compatibility_hole();
|
|
|
|
// Allocate memory
|
|
// FIXME: We shouldn't use this much memory really.
|
|
memset(&M, 0, sizeof(X86EMU_sysEnv));
|
|
M.mem_base = malloc(EMULATOR_MEM_SIZE);
|
|
M.mem_size = EMULATOR_MEM_SIZE;
|
|
|
|
if (!M.mem_base)
|
|
{
|
|
PRINTF("Unable to allocate one megabyte for emulator\n");
|
|
return 0;
|
|
}
|
|
|
|
if (attempt_map_rom(gr_dev, M.mem_base + EMULATOR_BIOS_OFFSET) == 0)
|
|
{
|
|
PRINTF("Error mapping rom. Emulation terminated\n");
|
|
return 0;
|
|
}
|
|
|
|
#if 1 /*def DEBUG*/
|
|
s = getenv("x86_ask_start");
|
|
if (s)
|
|
{
|
|
printf("Press 'q' to skip initialization, 'd' for dry init\n'i' for i/o session");
|
|
while (!tstc());
|
|
c = getc();
|
|
if (c == 'q') return 0;
|
|
if (c == 'd')
|
|
{
|
|
extern void bios_set_mode(int mode);
|
|
bios_set_mode(0x03);
|
|
return 0;
|
|
}
|
|
if (c == 'i') do_inout();
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
#ifdef EASTEREGG
|
|
/* if (tstc())
|
|
{
|
|
if (getc() == 'c')
|
|
{
|
|
easteregg_active = 1;
|
|
}
|
|
}
|
|
*/
|
|
if (getenv("easteregg"))
|
|
{
|
|
easteregg_active = 1;
|
|
}
|
|
|
|
if (easteregg_active)
|
|
{
|
|
// Yay!
|
|
setenv("x86_mode", "1");
|
|
setenv("vga_fg_color", "11");
|
|
setenv("vga_bg_color", "1");
|
|
easteregg_active = 1;
|
|
}
|
|
#endif
|
|
|
|
strap = (u8*)M.mem_base + EMULATOR_STRAP_OFFSET;
|
|
|
|
{
|
|
char *m = getenv("x86_mode");
|
|
if (m)
|
|
{
|
|
more_strap[3] = atoi(m);
|
|
if (more_strap[3] == 1) video_size(40, 25);
|
|
else video_size(80, 25);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Poke the strap routine. This might need a bit of extending
|
|
* if there is a mode switch involved, i.e. we want to int10
|
|
* afterwards to set a different graphics mode, or alternatively
|
|
* there might be a different start address requirement if the
|
|
* ROM doesn't have an x86 image in its first image.
|
|
*/
|
|
|
|
PRINTF("Poking strap...\n");
|
|
|
|
// FAR CALL c000:0003
|
|
*strap++ = 0x9A; *strap++ = 0x03; *strap++ = 0x00;
|
|
*strap++ = 0x00; *strap++ = 0xC0;
|
|
|
|
#if 1
|
|
// insert additional strap code
|
|
for (i=0; i < MORE_STRAP_BYTES; i++)
|
|
{
|
|
*strap++ = more_strap[i];
|
|
}
|
|
#endif
|
|
// HALT
|
|
*strap++ = 0xF4;
|
|
|
|
PRINTF("Setting up logo data\n");
|
|
logo = (unsigned char *)M.mem_base + EMULATOR_LOGO_OFFSET;
|
|
for (i=0; i<16; i++)
|
|
{
|
|
*logo++ = 0xFF;
|
|
}
|
|
|
|
/*
|
|
* Setup the init parameters.
|
|
* Per PCI specs, AH must contain the bus and AL
|
|
* must contain the devfn, encoded as (dev<<3)|fn
|
|
*/
|
|
|
|
// Execution starts here
|
|
M.x86.R_CS = SEG(EMULATOR_STRAP_OFFSET);
|
|
M.x86.R_IP = OFF(EMULATOR_STRAP_OFFSET);
|
|
|
|
// Stack at top of ram
|
|
M.x86.R_SS = SEG(EMULATOR_STACK_OFFSET);
|
|
M.x86.R_SP = OFF(EMULATOR_STACK_OFFSET);
|
|
|
|
// Input parameters
|
|
M.x86.R_AH = PCI_BUS(gr_dev);
|
|
M.x86.R_AL = (PCI_DEV(gr_dev)<<3) | PCI_FUNC(gr_dev);
|
|
|
|
// Set the I/O and memory access functions
|
|
X86EMU_setupMemFuncs(&_A1_mem);
|
|
X86EMU_setupPioFuncs(&_A1_pio);
|
|
|
|
// Enable timer 2
|
|
cfg = in_byte(0x61); // Get Misc control
|
|
cfg |= 0x01; // Enable timer 2
|
|
out_byte(0x61, cfg); // output again
|
|
|
|
// Set up the timers
|
|
out_byte(0x43, 0x54);
|
|
out_byte(0x41, 0x18);
|
|
|
|
out_byte(0x43, 0x36);
|
|
out_byte(0x40, 0x00);
|
|
out_byte(0x40, 0x00);
|
|
|
|
out_byte(0x43, 0xb6);
|
|
out_byte(0x42, 0x31);
|
|
out_byte(0x42, 0x13);
|
|
|
|
// Init the "BIOS".
|
|
bios_init();
|
|
|
|
// Video Card Reset
|
|
out_byte(0x3D8, 0);
|
|
out_byte(0x3B8, 1);
|
|
(void)in_byte(0x3BA);
|
|
(void)in_byte(0x3DA);
|
|
out_byte(0x3C0, 0);
|
|
out_byte(0x61, 0xFC);
|
|
|
|
#ifdef DEBUG
|
|
s = _getenv("x86_singlestep");
|
|
if (s && strcmp(s, "on")==0)
|
|
{
|
|
PRINTF("Enabling single stepping for debug\n");
|
|
X86EMU_trace_on();
|
|
}
|
|
#endif
|
|
|
|
// Ready set go...
|
|
PRINTF("Running emulator\n");
|
|
X86EMU_exec();
|
|
PRINTF("Done running emulator\n");
|
|
|
|
/* FIXME: Remove me */
|
|
pal_reset = getenv("x86_palette_reset");
|
|
if (pal_reset && strcmp(pal_reset, "on") == 0)
|
|
{
|
|
PRINTF("Palette reset\n");
|
|
//(void)in_byte(0x3da);
|
|
//out_byte(0x3c0, 0);
|
|
|
|
out_byte(0x3C8, 0);
|
|
out_byte(0x3C9, 0);
|
|
out_byte(0x3C9, 0);
|
|
out_byte(0x3C9, 0);
|
|
for (i=0; i<254; i++)
|
|
{
|
|
out_byte(0x3C9, 63);
|
|
out_byte(0x3C9, 63);
|
|
out_byte(0x3C9, 63);
|
|
}
|
|
|
|
out_byte(0x3c0, 0x20);
|
|
}
|
|
/* FIXME: remove me */
|
|
#ifdef EASTEREGG
|
|
if (easteregg_active)
|
|
{
|
|
extern void video_easteregg(void);
|
|
video_easteregg();
|
|
}
|
|
#endif
|
|
/*
|
|
current_attr = video_get_attr();
|
|
fb = (u8 *)VIDEO_BASE;
|
|
for (i=0; i<video_rows()*video_cols()*2; i+=2)
|
|
{
|
|
*(fb+i) = ' ';
|
|
*(fb+i+1) = current_attr;
|
|
}
|
|
|
|
fb = (u8 *)VIDEO_BASE + (video_rows())-1*(video_cols()*2);
|
|
for (i=0; i<video_cols(); i++)
|
|
{
|
|
*(fb + 2*i) = 32;
|
|
*(fb + 2*i + 1) = 0x17;
|
|
}
|
|
|
|
msg = done_msg;
|
|
while (*msg)
|
|
{
|
|
*fb = *msg;
|
|
fb += 2;
|
|
msg ++;
|
|
}
|
|
*/
|
|
#ifdef DEBUG
|
|
if (getenv("x86_do_inout")) do_inout();
|
|
#endif
|
|
|
|
//FIXME: dcache_disable();
|
|
return 1;
|
|
}
|
|
|
|
// Clean up the x86 mess
|
|
void shutdown_bios(void)
|
|
{
|
|
// disable_compatibility_hole();
|
|
// Free the memory associated
|
|
free(M.mem_base);
|
|
|
|
}
|
|
|
|
int to_int(char *buffer)
|
|
{
|
|
int base = 0;
|
|
int res = 0;
|
|
|
|
if (*buffer == '$')
|
|
{
|
|
base = 16;
|
|
buffer++;
|
|
}
|
|
else base = 10;
|
|
|
|
for (;;)
|
|
{
|
|
switch(*buffer)
|
|
{
|
|
case '0' ... '9':
|
|
res *= base;
|
|
res += *buffer - '0';
|
|
break;
|
|
case 'A':
|
|
case 'a':
|
|
res *= base;
|
|
res += 10;
|
|
break;
|
|
case 'B':
|
|
case 'b':
|
|
res *= base;
|
|
res += 11;
|
|
break;
|
|
case 'C':
|
|
case 'c':
|
|
res *= base;
|
|
res += 12;
|
|
break;
|
|
case 'D':
|
|
case 'd':
|
|
res *= base;
|
|
res += 13;
|
|
break;
|
|
case 'E':
|
|
case 'e':
|
|
res *= base;
|
|
res += 14;
|
|
break;
|
|
case 'F':
|
|
case 'f':
|
|
res *= base;
|
|
res += 15;
|
|
break;
|
|
default:
|
|
return res;
|
|
}
|
|
buffer++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void one_arg(char *buffer, int *a)
|
|
{
|
|
while (*buffer && *buffer != '\n')
|
|
{
|
|
if (*buffer == ' ') buffer++;
|
|
else break;
|
|
}
|
|
|
|
*a = to_int(buffer);
|
|
}
|
|
|
|
void two_args(char *buffer, int *a, int *b)
|
|
{
|
|
while (*buffer && *buffer != '\n')
|
|
{
|
|
if (*buffer == ' ') buffer++;
|
|
else break;
|
|
}
|
|
|
|
*a = to_int(buffer);
|
|
|
|
while (*buffer && *buffer != '\n')
|
|
{
|
|
if (*buffer != ' ') buffer++;
|
|
else break;
|
|
}
|
|
|
|
while (*buffer && *buffer != '\n')
|
|
{
|
|
if (*buffer == ' ') buffer++;
|
|
else break;
|
|
}
|
|
|
|
*b = to_int(buffer);
|
|
}
|
|
|
|
void do_inout(void)
|
|
{
|
|
char buffer[256];
|
|
char *arg1, *arg2;
|
|
int a,b;
|
|
|
|
printf("In/Out Session\nUse 'i[bwl]' for in, 'o[bwl]' for out and 'q' to quit\n");
|
|
|
|
do
|
|
{
|
|
cons_gets(buffer);
|
|
printf("\n");
|
|
|
|
*arg1 = buffer;
|
|
while (*arg1 != ' ' ) arg1++;
|
|
while (*arg1 == ' ') arg1++;
|
|
|
|
if (buffer[0] == 'i')
|
|
{
|
|
one_arg(buffer+2, &a);
|
|
switch (buffer[1])
|
|
{
|
|
case 'b':
|
|
printf("in_byte(%xh) = %xh\n", a, A1_inb(a));
|
|
break;
|
|
case 'w':
|
|
printf("in_word(%xh) = %xh\n", a, A1_inw(a));
|
|
break;
|
|
case 'l':
|
|
printf("in_dword(%xh) = %xh\n", a, A1_inl(a));
|
|
break;
|
|
default:
|
|
printf("Invalid length '%c'\n", buffer[1]);
|
|
break;
|
|
}
|
|
}
|
|
else if (buffer[0] == 'o')
|
|
{
|
|
two_args(buffer+2, &a, &b);
|
|
switch (buffer[1])
|
|
{
|
|
case 'b':
|
|
printf("out_byte(%d, %d)\n", a, b);
|
|
A1_outb(a,b);
|
|
break;
|
|
case 'w':
|
|
printf("out_word(%d, %d)\n", a, b);
|
|
A1_outw(a, b);
|
|
break;
|
|
case 'l':
|
|
printf("out_long(%d, %d)\n", a, b);
|
|
A1_outl(a, b);
|
|
break;
|
|
default:
|
|
printf("Invalid length '%c'\n", buffer[1]);
|
|
break;
|
|
}
|
|
} else if (buffer[0] == 'q') return;
|
|
} while (1);
|
|
}
|
|
|