initial commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
#include "asm6502.h"
|
||||
|
||||
inline byte asm_np(byte * ip, AsmIns ins)
|
||||
{
|
||||
ip[0] = ins & 0xff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline byte asm_ac(byte * ip, AsmIns ins)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x08;
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline byte asm_zp(byte * ip, AsmIns ins, byte addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x04;
|
||||
ip[1] = addr;
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline byte asm_rl(byte * ip, AsmIns ins, sbyte addr)
|
||||
{
|
||||
ip[0] = ins & 0xff;
|
||||
ip[1] = (byte)addr;
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline byte asm_im(byte * ip, AsmIns ins, byte value)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | ((ins & 0x01) << 3);
|
||||
ip[1] = value;
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline byte asm_zx(byte * ip, AsmIns ins, byte addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x05;
|
||||
ip[1] = addr;
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline byte asm_zy(byte * ip, AsmIns ins, byte addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x05;
|
||||
ip[1] = addr;
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline byte asm_ab(byte * ip, AsmIns ins, unsigned addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) ^ 0x0c;
|
||||
ip[1] = addr & 0xff;
|
||||
ip[2] = addr >> 8;
|
||||
return 3;
|
||||
}
|
||||
|
||||
inline byte asm_in(byte * ip, AsmIns ins, unsigned addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) ^ 0x2c;
|
||||
ip[1] = addr & 0xff;
|
||||
ip[2] = addr >> 8;
|
||||
return 3;
|
||||
}
|
||||
|
||||
inline byte asm_ax(byte * ip, AsmIns ins, unsigned addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x1c;
|
||||
ip[1] = addr & 0xff;
|
||||
ip[2] = addr >> 8;
|
||||
return 3;
|
||||
}
|
||||
|
||||
inline byte asm_ay(byte * ip, AsmIns ins, unsigned addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x18;
|
||||
ip[1] = addr & 0xff;
|
||||
ip[2] = addr >> 8;
|
||||
return 3;
|
||||
}
|
||||
|
||||
inline byte asm_ix(byte * ip, AsmIns ins, byte addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x00;
|
||||
ip[1] = addr;
|
||||
return 2;
|
||||
}
|
||||
|
||||
inline byte asm_iy(byte * ip, AsmIns ins, byte addr)
|
||||
{
|
||||
ip[0] = (ins & 0xff) | 0x10;
|
||||
ip[1] = addr;
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
#ifndef C64_ASM_6502_H
|
||||
#define C64_ASM_6502_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// Base form for the 6502 instructions
|
||||
|
||||
enum AsmIns
|
||||
{
|
||||
// Implied
|
||||
|
||||
ASM_BRK = 0x00,
|
||||
|
||||
ASM_RTI = 0x40,
|
||||
ASM_RTS = 0x60,
|
||||
|
||||
ASM_PHP = 0x08,
|
||||
ASM_CLC = 0x18,
|
||||
ASM_PLP = 0x28,
|
||||
ASM_SEC = 0x38,
|
||||
ASM_PHA = 0x48,
|
||||
|
||||
ASM_CLI = 0x58,
|
||||
ASM_PLA = 0x68,
|
||||
ASM_SEI = 0x78,
|
||||
|
||||
ASM_DEY = 0x88,
|
||||
ASM_TYA = 0x98,
|
||||
ASM_TAY = 0xa8,
|
||||
ASM_CLV = 0xb8,
|
||||
|
||||
ASM_INY = 0xc8,
|
||||
ASM_CLD = 0xd8,
|
||||
ASM_INX = 0xe8,
|
||||
ASM_SED = 0xf8,
|
||||
|
||||
ASM_TXA = 0x8a,
|
||||
ASM_TXS = 0x9a,
|
||||
ASM_TAX = 0xaa,
|
||||
ASM_TSX = 0xba,
|
||||
ASM_DEX = 0xca,
|
||||
ASM_NOP = 0xea,
|
||||
|
||||
// Relative
|
||||
ASM_BPL = 0x10,
|
||||
ASM_BMI = 0x30,
|
||||
ASM_BVC = 0x50,
|
||||
ASM_BVS = 0x70,
|
||||
ASM_BCC = 0x90,
|
||||
ASM_BCS = 0xb0,
|
||||
ASM_BNE = 0xd0,
|
||||
ASM_BEQ = 0xf0,
|
||||
|
||||
// Generic address
|
||||
ASM_ORA = 0x01,
|
||||
ASM_AND = 0x21,
|
||||
ASM_EOR = 0x41,
|
||||
ASM_ADC = 0x61,
|
||||
ASM_STA = 0x81,
|
||||
ASM_LDA = 0xa1,
|
||||
ASM_CMP = 0xc1,
|
||||
ASM_SBC = 0xe1,
|
||||
|
||||
ASM_STY = 0x80,
|
||||
ASM_LDY = 0xa0,
|
||||
ASM_CPY = 0xc0,
|
||||
ASM_CPX = 0xe0,
|
||||
|
||||
ASM_ASL = 0x02,
|
||||
ASM_ROL = 0x22,
|
||||
ASM_LSR = 0x42,
|
||||
ASM_ROR = 0x62,
|
||||
|
||||
ASM_STX = 0x82,
|
||||
ASM_LDX = 0xa2,
|
||||
ASM_DEC = 0xc2,
|
||||
ASM_INC = 0xe2,
|
||||
|
||||
// Limited Generic
|
||||
ASM_BIT = 0x20,
|
||||
|
||||
// Jump
|
||||
ASM_JMP = 0x40,
|
||||
ASM_JSR = 0x2c
|
||||
};
|
||||
|
||||
// the asm_ instructions emit a machine instruction at the given
|
||||
// location and return the size.
|
||||
|
||||
// implied
|
||||
inline byte asm_np(byte * ip, AsmIns ins);
|
||||
|
||||
// accu (e.g. rol/ror)
|
||||
inline byte asm_ac(byte * ip, AsmIns ins);
|
||||
|
||||
// zero page
|
||||
inline byte asm_zp(byte * ip, AsmIns ins, byte addr);
|
||||
|
||||
// relative branch
|
||||
inline byte asm_rl(byte * ip, AsmIns ins, sbyte addr);
|
||||
|
||||
// immediate
|
||||
inline byte asm_im(byte * ip, AsmIns ins, byte value);
|
||||
|
||||
// zero page indexed by x
|
||||
inline byte asm_zx(byte * ip, AsmIns ins, byte addr);
|
||||
|
||||
// zero page indexed by y
|
||||
inline byte asm_zy(byte * ip, AsmIns ins, byte addr);
|
||||
|
||||
// absolute
|
||||
inline byte asm_ab(byte * ip, AsmIns ins, unsigned addr);
|
||||
|
||||
// indirect (jmp)
|
||||
inline byte asm_in(byte * ip, AsmIns ins, unsigned addr);
|
||||
|
||||
// absolute indexed by x
|
||||
inline byte asm_ax(byte * ip, AsmIns ins, unsigned addr);
|
||||
|
||||
// absolute indexed by y
|
||||
inline byte asm_ay(byte * ip, AsmIns ins, unsigned addr);
|
||||
|
||||
// zero page indirect indexed by x
|
||||
inline byte asm_ix(byte * ip, AsmIns ins, byte addr);
|
||||
|
||||
// zero page indirect indexed by y
|
||||
inline byte asm_iy(byte * ip, AsmIns ins, byte addr);
|
||||
|
||||
#pragma compile("asm6502.c")
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,985 @@
|
||||
#include "charwin.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static const unsigned mul40[25] = {
|
||||
0, 40, 80, 120, 160,
|
||||
200, 240, 280, 320, 360,
|
||||
400, 440, 480, 520, 560,
|
||||
600, 640, 680, 720, 760,
|
||||
800, 840, 880, 920, 960
|
||||
};
|
||||
|
||||
static __native inline void copy_fwd(char * sdp, const char * ssp, char * cdp, const char * csp, char n)
|
||||
{
|
||||
for(char i=0; i<n; i++)
|
||||
{
|
||||
sdp[i] = ssp[i];
|
||||
cdp[i] = csp[i];
|
||||
}
|
||||
}
|
||||
|
||||
static __native inline void fill_fwd(char * sdp, char * cdp, char ch, char color, char n)
|
||||
{
|
||||
for(char i=0; i<n; i++)
|
||||
{
|
||||
sdp[i] = ch;
|
||||
cdp[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
static __native inline void copy_bwd(char * sdp, const char * ssp, char * cdp, const char * csp, char n)
|
||||
{
|
||||
while (n)
|
||||
{
|
||||
n--;
|
||||
sdp[n] = ssp[n];
|
||||
cdp[n] = csp[n];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cwin_init(CharWin * win, char * screen, char sx, char sy, char wx, char wy)
|
||||
{
|
||||
win->sx = sx;
|
||||
win->sy = sy;
|
||||
win->wx = wx;
|
||||
win->wy = wy;
|
||||
win->cx = 0;
|
||||
win->cy = 0;
|
||||
win->sp = screen + mul40[sy] + sx;
|
||||
win->cp = (char *)0xd800 + mul40[sy] + sx;
|
||||
}
|
||||
|
||||
|
||||
void cwin_clear(CharWin * win)
|
||||
{
|
||||
cwin_fill(win, ' ', 1);
|
||||
}
|
||||
|
||||
void cwin_fill(CharWin * win, char ch, char color)
|
||||
{
|
||||
char *sp = win->sp, * cp = win->cp;
|
||||
for(char y=0; y<win->wy; y++)
|
||||
{
|
||||
fill_fwd(sp, cp, ch, color, win->wx);
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void cwin_cursor_show(CharWin * win, bool show)
|
||||
{
|
||||
char * cp = win->sp + mul40[win->cy] + win->cx;
|
||||
if (show)
|
||||
*cp |= 0x80;
|
||||
else
|
||||
*cp &= 0x7f;
|
||||
}
|
||||
|
||||
void cwin_cursor_move(CharWin * win, char cx, char cy)
|
||||
{
|
||||
win->cx = cx;
|
||||
win->cy = cy;
|
||||
}
|
||||
|
||||
|
||||
bool cwin_cursor_left(CharWin * win)
|
||||
{
|
||||
if (win->cx > 0)
|
||||
{
|
||||
win->cx--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_cursor_right(CharWin * win)
|
||||
{
|
||||
if (win->cx + 1 < win->wx)
|
||||
{
|
||||
win->cx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_cursor_up(CharWin * win)
|
||||
{
|
||||
if (win->cy > 0)
|
||||
{
|
||||
win->cy--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_cursor_down(CharWin * win)
|
||||
{
|
||||
if (win->cy + 1 < win->wy)
|
||||
{
|
||||
win->cy++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_cursor_newline(CharWin * win)
|
||||
{
|
||||
win->cx = 0;
|
||||
if (win->cy + 1 < win->wy)
|
||||
{
|
||||
win->cy++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_cursor_forward(CharWin * win)
|
||||
{
|
||||
if (win->cx + 1 < win->wx)
|
||||
{
|
||||
win->cx++;
|
||||
return true;
|
||||
}
|
||||
else if (win->cy + 1 < win->wy)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_cursor_backward(CharWin * win)
|
||||
{
|
||||
if (win->cx > 0)
|
||||
{
|
||||
win->cx--;
|
||||
return true;
|
||||
}
|
||||
else if (win->cy > 0)
|
||||
{
|
||||
win->cx = win->wx - 1;
|
||||
win->cy--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//static char p2smap[] = {0x00, 0x20, 0x00, 0x40, 0x00, 0x60, 0x40, 0x60};
|
||||
static char p2smap[] = {0x00, 0x00, 0x40, 0x20, 0x80, 0xc0, 0x80, 0x80};
|
||||
//static char s2pmap[] = {0x40, 0x20, 0x60, 0xa0, 0x40, 0x20, 0x60, 0xa0};
|
||||
static char s2pmap[] = {0x40, 0x00, 0x20, 0xc0, 0xc0, 0x80, 0xa0, 0x40};
|
||||
|
||||
static inline char p2s(char ch)
|
||||
{
|
||||
return ch ^ p2smap[ch >> 5];
|
||||
}
|
||||
|
||||
static inline char s2p(char ch)
|
||||
{
|
||||
return ch ^ s2pmap[ch >> 5];
|
||||
}
|
||||
|
||||
void cwin_read_string(CharWin * win, char * buffer)
|
||||
{
|
||||
char * sp = win->sp;
|
||||
|
||||
char i = 0;
|
||||
for(char y=0; y<win->wy; y++)
|
||||
{
|
||||
for(char x=0; x<win->wx; x++)
|
||||
{
|
||||
buffer[i++] = s2p(sp[x]);
|
||||
}
|
||||
sp += 40;
|
||||
}
|
||||
while (i > 0 && buffer[i - 1] == ' ')
|
||||
i--;
|
||||
buffer[i] = 0;
|
||||
}
|
||||
|
||||
void cwin_write_string(CharWin * win, const char * buffer)
|
||||
{
|
||||
char * dp = win->sp;
|
||||
for(char y=0; y<win->wy; y++)
|
||||
{
|
||||
for(char x=0; x<win->wx; x++)
|
||||
{
|
||||
char ch = *buffer;
|
||||
if (ch)
|
||||
{
|
||||
dp[x] = p2s(ch);
|
||||
buffer++;
|
||||
}
|
||||
else
|
||||
dp[x] = ' ';
|
||||
}
|
||||
dp += 40;
|
||||
}
|
||||
|
||||
}
|
||||
void cwin_put_char(CharWin * win, char ch, char color)
|
||||
{
|
||||
cwin_putat_char(win, win->cx, win->cy, ch, color);
|
||||
win->cx++;
|
||||
if (win->cx == win->wx)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_put_chars(CharWin * win, const char * chars, char num, char color)
|
||||
{
|
||||
cwin_putat_chars(win, win->cx, win->cy, chars, color);
|
||||
win->cx += num;
|
||||
if (win->cx >= win->wx)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
}
|
||||
}
|
||||
|
||||
char cwin_put_string(CharWin * win, const char * str, char color)
|
||||
{
|
||||
char n = cwin_putat_string(win, win->cx, win->cy, str, color);
|
||||
win->cx += n;
|
||||
if (win->cx >= win->wx)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void cwin_put_char_raw(CharWin * win, char ch, char color)
|
||||
{
|
||||
cwin_putat_char_raw(win, win->cx, win->cy, ch, color);
|
||||
win->cx++;
|
||||
if (win->cx == win->wx)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_put_chars_raw(CharWin * win, const char * chars, char num, char color)
|
||||
{
|
||||
cwin_putat_chars_raw(win, win->cx, win->cy, chars, color);
|
||||
win->cx += num;
|
||||
if (win->cx >= win->wx)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
}
|
||||
}
|
||||
|
||||
char cwin_put_string_raw(CharWin * win, const char * str, char color)
|
||||
{
|
||||
char n = cwin_putat_string_raw(win, win->cx, win->cy, str, color);
|
||||
win->cx += n;
|
||||
if (win->cx >= win->wx)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cwin_putat_char(CharWin * win, char x, char y, char ch, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
win->sp[offset] = p2s(ch);
|
||||
win->cp[offset] = color;
|
||||
}
|
||||
|
||||
#pragma native(cwin_putat_char)
|
||||
|
||||
void cwin_putat_chars(CharWin * win, char x, char y, const char * chars, char num, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
char * cp = win->cp + offset;
|
||||
|
||||
for(char i=0; i<num; i++)
|
||||
{
|
||||
char ch = chars[i];
|
||||
|
||||
sp[i] = p2s(ch);
|
||||
cp[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(cwin_putat_chars)
|
||||
|
||||
char cwin_putat_string(CharWin * win, char x, char y, const char * str, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
char * cp = win->cp + offset;
|
||||
|
||||
char i = 0;
|
||||
while (char ch = str[i])
|
||||
{
|
||||
sp[i] = p2s(ch);
|
||||
cp[i] = color;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#pragma native(cwin_putat_string)
|
||||
|
||||
void cwin_putat_char_raw(CharWin * win, char x, char y, char ch, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
win->sp[offset] = ch;
|
||||
win->cp[offset] = color;
|
||||
}
|
||||
|
||||
#pragma native(cwin_putat_char_raw)
|
||||
|
||||
void cwin_putat_chars_raw(CharWin * win, char x, char y, const char * chars, char num, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
char * cp = win->cp + offset;
|
||||
|
||||
for(char i=0; i<num; i++)
|
||||
{
|
||||
char ch = chars[i];
|
||||
|
||||
sp[i] = ch;
|
||||
cp[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(cwin_putat_chars_raw)
|
||||
|
||||
char cwin_putat_string_raw(CharWin * win, char x, char y, const char * str, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
char * cp = win->cp + offset;
|
||||
|
||||
char i = 0;
|
||||
while (char ch = str[i])
|
||||
{
|
||||
sp[i] = ch;
|
||||
cp[i] = color;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#pragma native(cwin_putat_string_raw)
|
||||
|
||||
char cwin_getat_char(CharWin * win, char x, char y)
|
||||
{
|
||||
char * sp = win->sp + mul40[y] + x;
|
||||
|
||||
return s2p(*sp);
|
||||
}
|
||||
|
||||
#pragma native(cwin_getat_char)
|
||||
|
||||
void cwin_getat_chars(CharWin * win, char x, char y, char * chars, char num)
|
||||
{
|
||||
char * sp = win->sp + mul40[y] + x;
|
||||
|
||||
for(char i=0; i<num; i++)
|
||||
{
|
||||
chars[i] = s2p(sp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(cwin_getat_chars)
|
||||
|
||||
char cwin_getat_char_raw(CharWin * win, char x, char y)
|
||||
{
|
||||
char * sp = win->sp + mul40[y] + x;
|
||||
|
||||
return *sp;
|
||||
}
|
||||
|
||||
#pragma native(cwin_getat_chars_raw)
|
||||
|
||||
void cwin_getat_chars_raw(CharWin * win, char x, char y, char * chars, char num)
|
||||
{
|
||||
char * sp = win->sp + mul40[y] + x;
|
||||
|
||||
for(char i=0; i<num; i++)
|
||||
{
|
||||
chars[i] = sp[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma native(cwin_put_rect_raw)
|
||||
|
||||
void cwin_put_rect_raw(CharWin * win, char x, char y, char w, char h, const char * chars, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
char * cp = win->cp + offset;
|
||||
|
||||
for(char i=0; i<h; i++)
|
||||
{
|
||||
|
||||
for(char j=0; j<w; j++)
|
||||
{
|
||||
sp[j] = chars[j];
|
||||
cp[j] = color;
|
||||
}
|
||||
|
||||
chars += w;
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(cwin_put_rect)
|
||||
|
||||
void cwin_put_rect(CharWin * win, char x, char y, char w, char h, const char * chars, char color)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
char * cp = win->cp + offset;
|
||||
|
||||
for(char i=0; i<h; i++)
|
||||
{
|
||||
|
||||
for(char j=0; j<w; j++)
|
||||
{
|
||||
sp[j] = p2s(chars[j]);
|
||||
cp[j] = color;
|
||||
}
|
||||
|
||||
chars += w;
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(cwin_get_rect_raw)
|
||||
|
||||
void cwin_get_rect_raw(CharWin * win, char x, char y, char w, char h, char * chars)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
|
||||
for(char i=0; i<h; i++)
|
||||
{
|
||||
|
||||
for(char j=0; j<w; j++)
|
||||
{
|
||||
chars[j] = sp[j];
|
||||
}
|
||||
|
||||
chars += w;
|
||||
sp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(cwin_get_rect)
|
||||
|
||||
void cwin_get_rect(CharWin * win, char x, char y, char w, char h, char * chars)
|
||||
{
|
||||
int offset = mul40[y] + x;
|
||||
|
||||
char * sp = win->sp + offset;
|
||||
|
||||
for(char i=0; i<h; i++)
|
||||
{
|
||||
|
||||
for(char j=0; j<w; j++)
|
||||
{
|
||||
chars[j] = s2p(sp[j]);
|
||||
}
|
||||
|
||||
chars += w;
|
||||
sp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma native(cwin_getat_chars_raw)
|
||||
|
||||
void cwin_insert_char_raw(CharWin * win, char ch, char color)
|
||||
{
|
||||
char y = win->wy - 1, rx = win->wx - 1;
|
||||
|
||||
char * sp = win->sp + mul40[y];
|
||||
char * cp = win->cp + mul40[y];
|
||||
|
||||
while (y > win->cy)
|
||||
{
|
||||
copy_bwd(sp + 1, sp, cp + 1, cp, rx);
|
||||
|
||||
sp -= 40;
|
||||
cp -= 40;
|
||||
sp[40] = sp[rx];
|
||||
cp[40] = cp[rx];
|
||||
y--;
|
||||
}
|
||||
|
||||
sp += win->cx;
|
||||
cp += win->cx;
|
||||
rx -= win->cx;
|
||||
|
||||
copy_bwd(sp + 1, sp, cp + 1, cp, rx);
|
||||
|
||||
sp[0] = ch;
|
||||
cp[0] = color;
|
||||
}
|
||||
|
||||
void cwin_insert_char(CharWin * win, char ch, char color)
|
||||
{
|
||||
cwin_insert_char_raw(win, p2s(ch), color);
|
||||
}
|
||||
|
||||
void cwin_delete_char(CharWin * win)
|
||||
{
|
||||
char * sp = win->sp + mul40[win->cy];
|
||||
char * cp = win->cp + mul40[win->cy];
|
||||
|
||||
char x = win->cx, rx = win->wx - 1;
|
||||
|
||||
copy_fwd(sp + x, sp + x + 1, cp + x, cp + x + 1, rx - x);
|
||||
|
||||
char y = win->cy + 1;
|
||||
while (y < win->wy)
|
||||
{
|
||||
sp[rx] = sp[40];
|
||||
cp[rx] = cp[40];
|
||||
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
|
||||
copy_fwd(sp, sp + 1, cp, cp + 1, rx);
|
||||
|
||||
y++;
|
||||
}
|
||||
|
||||
sp[rx] = ' ';
|
||||
}
|
||||
|
||||
int cwin_getch(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
L1:
|
||||
jsr 0xffe4
|
||||
cmp #0
|
||||
beq L1
|
||||
sta accu
|
||||
lda #0
|
||||
sta accu + 1
|
||||
}
|
||||
}
|
||||
|
||||
int cwin_checkch(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
L1:
|
||||
jsr 0xffe4
|
||||
sta accu
|
||||
lda #0
|
||||
sta accu + 1
|
||||
}
|
||||
}
|
||||
|
||||
bool cwin_edit_char(CharWin * win, char ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 13:
|
||||
case 3:
|
||||
return true;
|
||||
|
||||
case 19:
|
||||
win->cx = 0;
|
||||
win->cy = 0;
|
||||
return false;
|
||||
|
||||
case 147:
|
||||
cwin_clear(win);
|
||||
win->cx = 0;
|
||||
win->cy = 0;
|
||||
return false;
|
||||
|
||||
case 17:
|
||||
cwin_cursor_down(win);
|
||||
return false;
|
||||
|
||||
case 145: // CRSR_UP
|
||||
cwin_cursor_up(win);
|
||||
return false;
|
||||
|
||||
case 29:
|
||||
cwin_cursor_forward(win);
|
||||
return false;
|
||||
|
||||
case 157:
|
||||
cwin_cursor_backward(win);
|
||||
return false;
|
||||
|
||||
case 20:
|
||||
if (cwin_cursor_backward(win))
|
||||
cwin_delete_char(win);
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (ch >= 32 && ch < 128 || ch >= 160)
|
||||
{
|
||||
if (win->cy + 1 < win->wy || win->cx + 1 < win->wx)
|
||||
{
|
||||
cwin_insert_char(win, ch, 1);
|
||||
cwin_cursor_forward(win);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char cwin_edit(CharWin * win)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
cwin_cursor_show(win, true);
|
||||
char ch = cwin_getch();
|
||||
cwin_cursor_show(win, false);
|
||||
|
||||
if (cwin_edit_char(win, ch))
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_scroll_left(CharWin * win, char by)
|
||||
{
|
||||
char * sp = win->sp;
|
||||
char * cp = win->cp;
|
||||
|
||||
char rx = win->wx - by;
|
||||
|
||||
for(char y=0; y<win->wy; y++)
|
||||
{
|
||||
copy_fwd(sp, sp + by, cp, cp + by, rx);
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_scroll_right(CharWin * win, char by)
|
||||
{
|
||||
char * sp = win->sp;
|
||||
char * cp = win->cp;
|
||||
|
||||
char rx = win->wx - by;
|
||||
|
||||
for(char y=0; y<win->wy; y++)
|
||||
{
|
||||
copy_bwd(sp + by, sp, cp + by, cp, rx);
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_scroll_up(CharWin * win, char by)
|
||||
{
|
||||
char * sp = win->sp;
|
||||
char * cp = win->cp;
|
||||
|
||||
char rx = win->wx;
|
||||
int dst = mul40[by];
|
||||
|
||||
for(char y=0; y<win->wy - by; y++)
|
||||
{
|
||||
copy_fwd(sp, sp + dst, cp, cp + dst, rx);
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_scroll_down(CharWin * win, char by)
|
||||
{
|
||||
char * sp = win->sp + mul40[win->wy];
|
||||
char * cp = win->cp + mul40[win->wy];
|
||||
|
||||
char rx = win->wx;
|
||||
|
||||
int dst = mul40[by];
|
||||
|
||||
for(char y=0; y<win->wy - by; y++)
|
||||
{
|
||||
sp -= 40;
|
||||
cp -= 40;
|
||||
copy_bwd(sp, sp - dst, cp, cp - dst, rx);
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_fill_rect_raw(CharWin * win, char x, char y, char w, char h, char ch, char color)
|
||||
{
|
||||
if (w > 0)
|
||||
{
|
||||
char * sp = win->sp + mul40[y] + x;
|
||||
char * cp = win->cp + mul40[y] + x;
|
||||
|
||||
for(char y=0; y<h; y++)
|
||||
{
|
||||
fill_fwd(sp, cp, ch, color, w);
|
||||
sp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_fill_rect(CharWin * win, char x, char y, char w, char h, char ch, char color)
|
||||
{
|
||||
cwin_fill_rect_raw(win, x, y, w, h, p2s(ch), color);
|
||||
}
|
||||
|
||||
void cwin_console_scroll_up(CharWin * win)
|
||||
{
|
||||
win->cy--;
|
||||
win->ly--;
|
||||
cwin_scroll_up(win, 1);
|
||||
cwin_fill_rect(win, 0, win->wy - 1, win->wx, 1, ' ', 1);
|
||||
}
|
||||
|
||||
void cwin_console_newline(CharWin * win)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
if (win->cy == win->wy)
|
||||
cwin_console_scroll_up(win);
|
||||
}
|
||||
|
||||
void cwin_console_write_char(CharWin * win, char ch, char color)
|
||||
{
|
||||
if (win->cx == win->wx)
|
||||
cwin_console_newline(win);
|
||||
|
||||
int offset = mul40[win->cy] + win->cx;
|
||||
|
||||
win->sp[offset] = p2s(ch);
|
||||
win->cp[offset] = color;
|
||||
win->cx++;
|
||||
}
|
||||
|
||||
void cwin_console_write_string(CharWin * win, const char * chars, char color)
|
||||
{
|
||||
win->ly = win->cy;
|
||||
win->lx = win->cx;
|
||||
|
||||
char i = 0;
|
||||
while (char ch = chars[i])
|
||||
{
|
||||
if (ch == '\n')
|
||||
cwin_console_newline(win);
|
||||
else
|
||||
cwin_console_write_char(win, ch, color);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_console_clear(CharWin * win)
|
||||
{
|
||||
cwin_fill_rect(win, win->lx, win->ly, win->wx - win->lx, 1, ' ', 1);
|
||||
cwin_fill_rect(win, 0, win->ly + 1, win->wx, win->wy - win->ly - 1, ' ', 1);
|
||||
}
|
||||
|
||||
bool cwin_console_cursor_left(CharWin * win)
|
||||
{
|
||||
if (win->cy == win->ly)
|
||||
{
|
||||
if (win->cx > win->lx)
|
||||
{
|
||||
win->cx--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (win->cx > 0)
|
||||
{
|
||||
win->cx--;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
win->cy--;
|
||||
win->cx = win->wx - 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cwin_console_cursor_right(CharWin * win)
|
||||
{
|
||||
if (win->cx + 1 < win->wx)
|
||||
{
|
||||
win->cx++;
|
||||
return true;
|
||||
}
|
||||
else if (win->cy + 1 < win->wy)
|
||||
{
|
||||
win->cy++;
|
||||
win->cx = 0;
|
||||
return true;
|
||||
}
|
||||
else if (win->ly > 0)
|
||||
{
|
||||
win->cx = 0;
|
||||
win->cy++;
|
||||
cwin_console_scroll_up(win);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cwin_console_delete_char(CharWin * win)
|
||||
{
|
||||
cwin_delete_char(win);
|
||||
}
|
||||
|
||||
bool cwin_console_insert_char(CharWin * win, char ch, char color)
|
||||
{
|
||||
if (win->sp[mul40[win->wy - 1] + win->wx - 1] != ' ')
|
||||
{
|
||||
if (win->ly == 0)
|
||||
return false;
|
||||
cwin_console_scroll_up(win);
|
||||
}
|
||||
|
||||
cwin_insert_char(win, ch, color);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cwin_console_edit_char(CharWin * win, char ch, char color)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 13:
|
||||
case 3:
|
||||
case 17:
|
||||
case 145: // CRSR_UP
|
||||
return true;
|
||||
|
||||
case 19:
|
||||
win->cx = win->lx;
|
||||
win->cy = win->ly;
|
||||
return false;
|
||||
|
||||
case 147:
|
||||
cwin_console_clear(win);
|
||||
win->cx = win->lx;;
|
||||
win->cy = win->ly;
|
||||
return false;
|
||||
|
||||
case 29:
|
||||
cwin_console_cursor_right(win);
|
||||
return false;
|
||||
|
||||
case 157:
|
||||
cwin_console_cursor_left(win);
|
||||
return false;
|
||||
|
||||
case 20:
|
||||
if (cwin_console_cursor_left(win))
|
||||
cwin_console_delete_char(win);
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (ch >= 32 && ch < 128 || ch >= 160)
|
||||
{
|
||||
if (cwin_console_insert_char(win, ch, color))
|
||||
cwin_console_cursor_right(win);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char cwin_console_edit_string(CharWin * win, char color)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
cwin_cursor_show(win, true);
|
||||
char ch = cwin_getch();
|
||||
cwin_cursor_show(win, false);
|
||||
|
||||
if (cwin_console_edit_char(win, ch, color))
|
||||
{
|
||||
win->cx = win->lx;
|
||||
win->cy = win->ly;
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cwin_console_get_string(CharWin * win, char * chars, char size)
|
||||
{
|
||||
char i = 0;
|
||||
char y = win->ly, x = win->lx;
|
||||
char * cp = win->sp + mul40[y];
|
||||
|
||||
while (i < size)
|
||||
{
|
||||
chars[i++] = s2p(cp[x++]);
|
||||
if (x == win->wx)
|
||||
{
|
||||
if (y + 1 == win->wy)
|
||||
break;
|
||||
x = 0;
|
||||
cp += 40;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
while (i > 0 && chars[i - 1] == ' ')
|
||||
{
|
||||
i--;
|
||||
if (x == 0)
|
||||
{
|
||||
y--;
|
||||
x = win->wx;
|
||||
}
|
||||
else
|
||||
x--;
|
||||
}
|
||||
|
||||
win->cx = x;
|
||||
win->cy = y;
|
||||
|
||||
chars[i] = 0;
|
||||
}
|
||||
|
||||
char * sformat(char * buff, const char * fmt, int * fps, bool print);
|
||||
|
||||
void cwin_console_printf(CharWin * win, char color, const char * fmt, ...)
|
||||
{
|
||||
char buff[200];
|
||||
sformat(buff, fmt, (int *)&fmt + 1, false);
|
||||
cwin_console_write_string(win, buff, color);
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
#ifndef C64_CHARWIN_H
|
||||
#define C64_CHARWIN_H
|
||||
|
||||
struct CharWin
|
||||
{
|
||||
char sx, sy, wx, wy;
|
||||
char cx, cy, lx, ly;
|
||||
|
||||
char * sp, * cp;
|
||||
};
|
||||
|
||||
// Initialize the CharWin structure for the given screen and coordinates, does
|
||||
// not clear the window
|
||||
//
|
||||
void cwin_init(CharWin * win, char * screen, char sx, char sy, char wx, char wy);
|
||||
|
||||
|
||||
// Clear the window
|
||||
//
|
||||
void cwin_clear(CharWin * win);
|
||||
|
||||
// Fill the window with the given character and color
|
||||
//
|
||||
void cwin_fill(CharWin * win, char ch, char color);
|
||||
|
||||
|
||||
// Show or hide the cursor by setting or clearing the MSB of the character code
|
||||
//
|
||||
void cwin_cursor_show(CharWin * win, bool show);
|
||||
|
||||
// Move the cursor to the given location
|
||||
//
|
||||
void cwin_cursor_move(CharWin * win, char cx, char cy);
|
||||
|
||||
|
||||
// Move the cursor in the window, returns true if the cursor could be moved
|
||||
//
|
||||
bool cwin_cursor_left(CharWin * win);
|
||||
bool cwin_cursor_right(CharWin * win);
|
||||
bool cwin_cursor_up(CharWin * win);
|
||||
bool cwin_cursor_down(CharWin * win);
|
||||
bool cwin_cursor_forward(CharWin * win);
|
||||
bool cwin_cursor_backward(CharWin * win);
|
||||
bool cwin_cursor_newline(CharWin * win);
|
||||
|
||||
// Read the full window into a string
|
||||
//
|
||||
void cwin_read_string(CharWin * win, char * buffer);
|
||||
|
||||
// Write the fill window with the given string
|
||||
//
|
||||
void cwin_write_string(CharWin * win, const char * buffer);
|
||||
|
||||
// Put a single char at the cursor location and advance the cursor
|
||||
//
|
||||
void cwin_put_char(CharWin * win, char ch, char color);
|
||||
|
||||
// Put an array of chars at the cursor location and advance the cursor
|
||||
//
|
||||
void cwin_put_chars(CharWin * win, const char * chars, char num, char color);
|
||||
|
||||
// Put a zero terminated string at the cursor location and advance the cursor
|
||||
//
|
||||
char cwin_put_string(CharWin * win, const char * str, char color);
|
||||
|
||||
// Put a single raw char at the cursor location and advance the cursor
|
||||
//
|
||||
void cwin_put_char_raw(CharWin * win, char ch, char color);
|
||||
|
||||
// Put an array of raw chars at the cursor location and advance the cursor
|
||||
//
|
||||
void cwin_put_chars_raw(CharWin * win, const char * chars, char num, char color);
|
||||
|
||||
// Put a zero terminated raw string at the cursor location and advance the cursor
|
||||
//
|
||||
char cwin_put_string_raw(CharWin * win, const char * str, char color);
|
||||
|
||||
|
||||
|
||||
// Put a single char at the given window location
|
||||
//
|
||||
void cwin_putat_char(CharWin * win, char x, char y, char ch, char color);
|
||||
|
||||
// Put an array of chars at the given window location
|
||||
//
|
||||
void cwin_putat_chars(CharWin * win, char x, char y, const char * chars, char num, char color);
|
||||
|
||||
// Put a zero terminated string at the given window location
|
||||
//
|
||||
char cwin_putat_string(CharWin * win, char x, char y, const char * str, char color);
|
||||
|
||||
|
||||
// Put a single raw char at the given window location
|
||||
//
|
||||
void cwin_putat_char_raw(CharWin * win, char x, char y, char ch, char color);
|
||||
|
||||
// Put an array of raw chars at the given window location
|
||||
//
|
||||
void cwin_putat_chars_raw(CharWin * win, char x, char y, const char * chars, char num, char color);
|
||||
|
||||
// Put a zero terminated string at the given window location
|
||||
//
|
||||
char cwin_putat_string_raw(CharWin * win, char x, char y, const char * str, char color);
|
||||
|
||||
|
||||
// Get a single char at the given window location
|
||||
//
|
||||
char cwin_getat_char(CharWin * win, char x, char y);
|
||||
|
||||
// Get an array of chars at the given window location
|
||||
//
|
||||
void cwin_getat_chars(CharWin * win, char x, char y, char * chars, char num);
|
||||
|
||||
|
||||
|
||||
// Get a single char at the given window location
|
||||
//
|
||||
char cwin_getat_char_raw(CharWin * win, char x, char y);
|
||||
|
||||
// Get an array of chars at the given window location
|
||||
//
|
||||
void cwin_getat_chars_raw(CharWin * win, char x, char y, char * chars, char num);
|
||||
|
||||
|
||||
// Put an array of characters into a rectangle in the char win
|
||||
void cwin_put_rect_raw(CharWin * win, char x, char y, char w, char h, const char * chars, char color);
|
||||
|
||||
void cwin_put_rect(CharWin * win, char x, char y, char w, char h, const char * chars, char color);
|
||||
|
||||
// Get an array of characters from a rectangle of a char win
|
||||
void cwin_get_rect_raw(CharWin * win, char x, char y, char w, char h, char * chars);
|
||||
|
||||
void cwin_get_rect(CharWin * win, char x, char y, char w, char h, char * chars);
|
||||
|
||||
|
||||
|
||||
// Insert one space character at the cursor position
|
||||
//
|
||||
void cwin_insert_char_raw(CharWin * win, char ch, char color);
|
||||
|
||||
void cwin_insert_char(CharWin * win, char ch, char color);
|
||||
|
||||
// Delete the character at the cursor position
|
||||
//
|
||||
void cwin_delete_char(CharWin * win);
|
||||
|
||||
int cwin_getch(void);
|
||||
|
||||
int cwin_checkch(void);
|
||||
|
||||
// Edit the window position using the char as the input
|
||||
//
|
||||
bool cwin_edit_char(CharWin * win, char ch);
|
||||
|
||||
// Edit the window using keyboard input, returns the key the exited
|
||||
// the edit, either return or stop
|
||||
//
|
||||
char cwin_edit(CharWin * win);
|
||||
|
||||
// Scroll the window in the given direction, does not fill the new
|
||||
// empty space
|
||||
//
|
||||
void cwin_scroll_left(CharWin * win, char by);
|
||||
void cwin_scroll_right(CharWin * win, char by);
|
||||
void cwin_scroll_up(CharWin * win, char by);
|
||||
void cwin_scroll_down(CharWin * win, char by);
|
||||
|
||||
// Fill the given rectangle with the character and color
|
||||
//
|
||||
inline void cwin_fill_rect(CharWin * win, char x, char y, char w, char h, char ch, char color);
|
||||
|
||||
// Fill the given rectangle with the screen code and color
|
||||
//
|
||||
void cwin_fill_rect_raw(CharWin * win, char x, char y, char w, char h, char ch, char color);
|
||||
|
||||
|
||||
void cwin_console_newline(CharWin * win);
|
||||
|
||||
void cwin_console_scroll_up(CharWin * win);
|
||||
|
||||
void cwin_console_write_char(CharWin * win, char ch, char color);
|
||||
|
||||
void cwin_console_write_string(CharWin * win, const char * chars, char color);
|
||||
|
||||
void cwin_console_clear(CharWin * win);
|
||||
|
||||
bool cwin_console_cursor_left(CharWin * win);
|
||||
bool cwin_console_cursor_right(CharWin * win);
|
||||
bool cwin_console_cursor_up(CharWin * win);
|
||||
bool cwin_console_cursor_down(CharWin * win);
|
||||
|
||||
// Insert one space character at the cursor position
|
||||
//
|
||||
bool cwin_console_insert_char(CharWin * win, char ch, char color);
|
||||
|
||||
// Delete the character at the cursor position
|
||||
//
|
||||
void cwin_console_delete_char(CharWin * win);
|
||||
|
||||
bool cwin_console_edit_char(CharWin * win, char ch, char color);
|
||||
|
||||
char cwin_console_edit_string(CharWin * win, char color);
|
||||
|
||||
void cwin_console_get_string(CharWin * win, char * chars, char size);
|
||||
|
||||
void cwin_console_printf(CharWin * win, char color, const char * fmt, ...);
|
||||
|
||||
#pragma compile("charwin.c")
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "cia.h"
|
||||
|
||||
byte ciaa_pra_def;
|
||||
|
||||
void cia_init(void)
|
||||
{
|
||||
cia1.icr = 0x7f;
|
||||
cia2.icr = 0x7f;
|
||||
cia1.pra = 0x7f;
|
||||
cia1.cra = 0x08;
|
||||
cia1.crb = 0x08;
|
||||
cia2.cra = 0x08;
|
||||
cia2.crb = 0x08;
|
||||
|
||||
cia1.ddrb = 0x00;
|
||||
cia2.ddrb = 0x00;
|
||||
cia1.ddra = 0xff;
|
||||
|
||||
cia2.pra = 0x07;
|
||||
cia2.ddra = 0x3f;
|
||||
|
||||
char i0 = cia1.icr;
|
||||
char i1 = cia2.icr;
|
||||
|
||||
ciaa_pra_def = 0x7f;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef C64_CIA
|
||||
#define C64_CIA
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct CIA
|
||||
{
|
||||
volatile byte pra, prb;
|
||||
volatile byte ddra, ddrb;
|
||||
volatile word ta, tb;
|
||||
volatile byte todt, tods, todm, todh;
|
||||
volatile byte sdr;
|
||||
volatile byte icr;
|
||||
volatile byte cra, crb;
|
||||
};
|
||||
|
||||
#define cia1 (*((struct CIA *)0xdc00))
|
||||
#define cia2 (*((struct CIA *)0xdd00))
|
||||
|
||||
extern byte ciaa_pra_def;
|
||||
|
||||
void cia_init(void);
|
||||
|
||||
#pragma compile("cia.c")
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef C64_EASYFLASH_H
|
||||
#define C64_EASYFLASH_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct EasyFlash
|
||||
{
|
||||
volatile __memmap byte bank;
|
||||
byte pad1;
|
||||
volatile byte control;
|
||||
};
|
||||
|
||||
#define EFCTRL_GAME 0x01
|
||||
#define EFCTRL_EXROM 0x02
|
||||
#define EFCTRL_MODE 0x04
|
||||
#define EFCTRL_LED 0x80
|
||||
|
||||
|
||||
#define eflash (*(EasyFlash *)0xde00)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifdef EFPROX_SECTION
|
||||
#pragma code(EFPROX_SECTION)
|
||||
#endif
|
||||
|
||||
template<int back, class fn, class ... P>
|
||||
__noinline auto ef_call_p(P... p)
|
||||
{
|
||||
if (back != __bankof(fn))
|
||||
eflash.bank = __bankof(fn);
|
||||
auto r = fn(p...);
|
||||
if (back != 0xff && back != __bankof(fn))
|
||||
eflash.bank = back;
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef EFPROX_SECTION
|
||||
#pragma code(code)
|
||||
#endif
|
||||
|
||||
template<class fn>
|
||||
class EFlashCall
|
||||
{
|
||||
public:
|
||||
template<class ... P>
|
||||
__forceinline auto operator()(P ... p) const
|
||||
{
|
||||
switch(__bankof(0))
|
||||
{
|
||||
#for(i,64) case i: return ef_call_p<i, fn, P...>(p...);
|
||||
default:
|
||||
return ef_call_p<0xff, fn, P...>(p...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define EF_CALL(fn) EFlashCall<fn##_p> fn
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,608 @@
|
||||
#include "flossiec.h"
|
||||
#include <c64/iecbus.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
#ifndef FLOSSIEC_NODISPLAY
|
||||
#define FLOSSIEC_NODISPLAY 0
|
||||
#endif
|
||||
#ifndef FLOSSIEC_NOIRQ
|
||||
#define FLOSSIEC_NOIRQ 0
|
||||
#endif
|
||||
#ifndef FLOSSIEC_BORDER
|
||||
#define FLOSSIEC_BORDER 0
|
||||
#endif
|
||||
|
||||
|
||||
#define VIA_ATNIN 0x80
|
||||
#define VIA_ATNOUT 0x10
|
||||
|
||||
#define VIA_CLKOUT 0x08
|
||||
#define VIA_DATAOUT 0x02
|
||||
|
||||
#define VIA_CLKIN 0x04
|
||||
#define VIA_DATAIN 0x01
|
||||
|
||||
#define PORTB1 0x1800
|
||||
#define PORTB2 0x1c00
|
||||
|
||||
#define WR 0x1d
|
||||
|
||||
#ifdef FLOSSIEC_CODE
|
||||
#pragma code(FLOSSIEC_CODE)
|
||||
#endif
|
||||
#ifdef FLOSSIEC_BSS
|
||||
#pragma bss(FLOSSIEC_BSS)
|
||||
#endif
|
||||
|
||||
__asm diskcode
|
||||
{
|
||||
nop
|
||||
nop
|
||||
|
||||
lda #VIA_CLKOUT
|
||||
sta PORTB1
|
||||
|
||||
lda 0x0202
|
||||
sta 0x0c
|
||||
lda 0x0203
|
||||
sta 0x0d
|
||||
lda #$80
|
||||
sta 0x03
|
||||
|
||||
ldx #0
|
||||
l0:
|
||||
txa
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sta 0x0700,x
|
||||
inx
|
||||
bne l0
|
||||
|
||||
lr:
|
||||
lda 0x03
|
||||
bmi lr
|
||||
|
||||
sei
|
||||
|
||||
ldx #0
|
||||
l2:
|
||||
lda #0
|
||||
sta PORTB1
|
||||
lda 0x0600, x
|
||||
tay
|
||||
and #0x0f
|
||||
ora #VIA_DATAIN
|
||||
l1:
|
||||
bit PORTB1
|
||||
bne l1
|
||||
|
||||
l3:
|
||||
sta PORTB1
|
||||
|
||||
tya
|
||||
asl
|
||||
and #0x0a
|
||||
sta PORTB1
|
||||
|
||||
lda 0x0700,y
|
||||
nop
|
||||
sta PORTB1
|
||||
|
||||
asl
|
||||
nop
|
||||
and #0x0a
|
||||
sta PORTB1
|
||||
|
||||
inx
|
||||
bne l2
|
||||
|
||||
lda #VIA_CLKOUT
|
||||
sta PORTB1
|
||||
|
||||
|
||||
lda 0x0600
|
||||
beq w1
|
||||
sta 0x0c
|
||||
lda 0x0601
|
||||
sta 0x0d
|
||||
lda #$80
|
||||
sta 0x03
|
||||
cli
|
||||
bne lr
|
||||
w1:
|
||||
sta PORTB1
|
||||
|
||||
cli
|
||||
rts
|
||||
}
|
||||
|
||||
#define CIA2B_ATNOUT 0x08
|
||||
#define CIA2B_CLKOUT 0x10
|
||||
#define CIA2B_DATAOUT 0x20
|
||||
|
||||
#define CIA2B_CLKIN 0x40
|
||||
#define CIA2B_DATAIN 0x80
|
||||
|
||||
#define CIA2PRA 0xdd00
|
||||
|
||||
static char remap[256];
|
||||
static char rbuffer[256];
|
||||
static char xbuffer[256];
|
||||
static char flpos;
|
||||
static char xcmd;
|
||||
static char xi, xj;
|
||||
static char fldrive;
|
||||
static char flvxor;
|
||||
|
||||
__noinline void fl_read_buf(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
#if FLOSSIEC_NOIRQ
|
||||
php
|
||||
sei
|
||||
#endif
|
||||
|
||||
lda CIA2PRA
|
||||
and #~CIA2B_CLKOUT
|
||||
sta accu
|
||||
sta CIA2PRA
|
||||
and #~CIA2B_DATAOUT
|
||||
sta accu + 1
|
||||
|
||||
l0:
|
||||
lda CIA2PRA
|
||||
and #CIA2B_CLKIN
|
||||
beq l0
|
||||
#if !FLOSSIEC_NOIRQ
|
||||
php
|
||||
pla
|
||||
and #$04
|
||||
beq iq
|
||||
#endif
|
||||
ldy #0
|
||||
sec
|
||||
l1:
|
||||
ldx accu + 1
|
||||
#if !FLOSSIEC_NODISPLAY
|
||||
l2:
|
||||
lda 0xd012
|
||||
sbc #50
|
||||
bcc w1
|
||||
and #7
|
||||
beq l2
|
||||
#endif
|
||||
w1:
|
||||
stx CIA2PRA
|
||||
|
||||
#if FLOSSIEC_BORDER
|
||||
inc 0xd020
|
||||
#else
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
#endif
|
||||
ldx accu
|
||||
nop
|
||||
|
||||
lda CIA2PRA
|
||||
lsr
|
||||
lsr
|
||||
nop
|
||||
eor CIA2PRA
|
||||
lsr
|
||||
lsr
|
||||
nop
|
||||
eor CIA2PRA
|
||||
lsr
|
||||
lsr
|
||||
sec
|
||||
eor CIA2PRA
|
||||
stx CIA2PRA
|
||||
|
||||
sta rbuffer, y
|
||||
iny
|
||||
bne l1
|
||||
jmp done
|
||||
#if !FLOSSIEC_NOIRQ
|
||||
iq:
|
||||
ldy #0
|
||||
sec
|
||||
l1i:
|
||||
ldx accu + 1
|
||||
l2i:
|
||||
cli
|
||||
sei
|
||||
#if !FLOSSIEC_NODISPLAY
|
||||
lda 0xd012
|
||||
sbc #50
|
||||
bcc w1i
|
||||
and #7
|
||||
beq l2i
|
||||
w1i:
|
||||
#endif
|
||||
stx CIA2PRA
|
||||
|
||||
#if FLOSSIEC_BORDER
|
||||
inc 0xd020
|
||||
#else
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
#endif
|
||||
ldx accu
|
||||
nop
|
||||
|
||||
lda CIA2PRA
|
||||
lsr
|
||||
lsr
|
||||
nop
|
||||
eor CIA2PRA
|
||||
lsr
|
||||
lsr
|
||||
nop
|
||||
eor CIA2PRA
|
||||
lsr
|
||||
lsr
|
||||
sec
|
||||
eor CIA2PRA
|
||||
stx CIA2PRA
|
||||
|
||||
sta rbuffer, y
|
||||
iny
|
||||
bne l1i
|
||||
cli
|
||||
#endif
|
||||
done:
|
||||
|
||||
#if FLOSSIEC_NOIRQ
|
||||
plp
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline char flossiec_get(void)
|
||||
{
|
||||
if (!flpos)
|
||||
{
|
||||
fl_read_buf();
|
||||
flpos = 2;
|
||||
}
|
||||
return remap[rbuffer[flpos++]];
|
||||
}
|
||||
|
||||
void flossiec_decompress(void)
|
||||
{
|
||||
char i = 0, j = xj, cmd = xcmd;
|
||||
xi = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if (cmd & 0x80)
|
||||
{
|
||||
if (i < cmd)
|
||||
{
|
||||
char t = i - cmd;
|
||||
do {
|
||||
char ch = xbuffer[j++];
|
||||
xbuffer[i++] = ch;
|
||||
} while (i != t);
|
||||
cmd = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd -= i;
|
||||
do {
|
||||
char ch = xbuffer[j++];
|
||||
xbuffer[i++] = ch;
|
||||
} while (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char ch = flossiec_get();
|
||||
if (cmd)
|
||||
{
|
||||
xbuffer[i++] = ch;
|
||||
cmd--;
|
||||
if (!i)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = ch;
|
||||
if (!cmd)
|
||||
break;
|
||||
if (cmd & 0x80)
|
||||
{
|
||||
cmd ^= 0x7f;
|
||||
cmd++;
|
||||
j = i - flossiec_get();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xj = j;
|
||||
xcmd = cmd;
|
||||
}
|
||||
|
||||
inline char flossiec_get_lzo(void)
|
||||
{
|
||||
if (!xi)
|
||||
flossiec_decompress();
|
||||
return xbuffer[xi++];
|
||||
}
|
||||
|
||||
inline bool flossiec_eof(void)
|
||||
{
|
||||
return !remap[rbuffer[0]] && flpos >= remap[rbuffer[1]];
|
||||
}
|
||||
|
||||
char * flossiec_read(char * dp, unsigned size)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
*dp++ = flossiec_get();
|
||||
size--;
|
||||
}
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
char * flossiec_read_lzo(char * dp, unsigned size)
|
||||
{
|
||||
char i = xi;
|
||||
|
||||
dp -= i;
|
||||
size += i;
|
||||
|
||||
while (size)
|
||||
{
|
||||
if (!i)
|
||||
flossiec_decompress();
|
||||
|
||||
if (size >= 256)
|
||||
{
|
||||
do {
|
||||
dp[i] = xbuffer[i];
|
||||
i++;
|
||||
} while (i);
|
||||
dp += 256;
|
||||
size -= 256;
|
||||
}
|
||||
else
|
||||
{
|
||||
do {
|
||||
dp[i] = xbuffer[i];
|
||||
i++;
|
||||
} while (i != (char)size);
|
||||
dp += i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xi = i;
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
static void vxorcheck(void)
|
||||
{
|
||||
char vxor = cia2.pra & 7;
|
||||
vxor ^= vxor >> 2;
|
||||
vxor ^= 0xff;
|
||||
|
||||
if (vxor != flvxor)
|
||||
{
|
||||
flvxor = vxor;
|
||||
|
||||
for(int i=0; i<256; i++)
|
||||
{
|
||||
char j = i ^ vxor;
|
||||
char d = ((j & 0x11) << 3) |
|
||||
(j & 0x66) |
|
||||
((j & 0x88) >> 3);
|
||||
remap[i] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool flossiec_init(char drive)
|
||||
{
|
||||
fldrive = drive;
|
||||
flvxor = 0;
|
||||
|
||||
iec_open(drive, 2, "#2");
|
||||
iec_listen(drive, 2);
|
||||
for(char j=0; j<127; j++)
|
||||
iec_write(((char *)diskcode)[j]);
|
||||
iec_unlisten();
|
||||
|
||||
iec_close(drive, 2);
|
||||
|
||||
iec_open(drive, 15, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void flossiec_shutdown(void)
|
||||
{
|
||||
iec_close(fldrive, 15);
|
||||
}
|
||||
|
||||
|
||||
bool flossiec_open(char track, char sector)
|
||||
{
|
||||
iec_listen(fldrive, 15);
|
||||
iec_write(P'U');
|
||||
iec_write(P'4');
|
||||
iec_write(track);
|
||||
iec_write(sector);
|
||||
iec_unlisten();
|
||||
|
||||
cia2.pra |= CIA2B_DATAOUT;
|
||||
|
||||
|
||||
#if FLOSSIEC_NODISPLAY
|
||||
vic.ctrl1 &= ~VIC_CTRL1_DEN;
|
||||
#endif
|
||||
|
||||
vic_waitFrame();
|
||||
vxorcheck();
|
||||
vic_waitFrame();
|
||||
|
||||
flpos = 0;
|
||||
xi = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void flossiec_close(void)
|
||||
{
|
||||
cia2.pra |= CIA2B_DATAOUT;
|
||||
|
||||
#if FLOSSIEC_NODISPLAY
|
||||
vic.ctrl1 |= VIC_CTRL1_DEN;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool flosskio_init(char drive)
|
||||
{
|
||||
fldrive = drive;
|
||||
flvxor = 0;
|
||||
|
||||
krnio_setnam_n("#2", 2);
|
||||
krnio_open(2, drive, 2);
|
||||
krnio_write(2, (char *)diskcode, 128);
|
||||
krnio_close(2);
|
||||
|
||||
krnio_setnam_n(nullptr, 0);
|
||||
krnio_open(15, drive, 15);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void flosskio_shutdown(void)
|
||||
{
|
||||
krnio_close(15);
|
||||
}
|
||||
|
||||
|
||||
bool flosskio_open(char track, char sector)
|
||||
{
|
||||
krnio_chkout(15);
|
||||
krnio_chrout(P'U');
|
||||
krnio_chrout(P'4');
|
||||
krnio_chrout(track);
|
||||
krnio_chrout(sector);
|
||||
krnio_clrchn();
|
||||
|
||||
cia2.pra |= CIA2B_DATAOUT;
|
||||
|
||||
#if FLOSSIEC_NODISPLAY
|
||||
vic.ctrl1 &= ~VIC_CTRL1_DEN;
|
||||
#endif
|
||||
|
||||
vic_waitFrame();
|
||||
vxorcheck();
|
||||
vic_waitFrame();
|
||||
|
||||
flpos = 0;
|
||||
xi = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void flosskio_close(void)
|
||||
{
|
||||
cia2.pra |= CIA2B_DATAOUT;
|
||||
|
||||
#if FLOSSIEC_NODISPLAY
|
||||
vic.ctrl1 |= VIC_CTRL1_DEN;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool mapdir(const char * fnames, floss_blk * blks)
|
||||
{
|
||||
do {
|
||||
fl_read_buf();
|
||||
|
||||
char si = 0;
|
||||
do
|
||||
{
|
||||
if (remap[rbuffer[si + 2]] == 0x82)
|
||||
{
|
||||
char fname[17];
|
||||
char j = 0;
|
||||
while (j < 16 && remap[rbuffer[si + j + 5]] != 0xa0)
|
||||
{
|
||||
fname[j] = remap[rbuffer[si + j + 5]];
|
||||
j++;
|
||||
}
|
||||
fname[j] = 0;
|
||||
|
||||
char sj = 0;
|
||||
char k = 0;
|
||||
while (fnames[sj])
|
||||
{
|
||||
j = 0;
|
||||
while (fname[j] && fname[j] == fnames[sj])
|
||||
{
|
||||
j++;
|
||||
sj++;
|
||||
}
|
||||
if (!fname[j] && (!fnames[sj] || fnames[sj] == ','))
|
||||
{
|
||||
__assume(k < 128);
|
||||
blks[k].track = remap[rbuffer[si + 3]];
|
||||
blks[k].sector = remap[rbuffer[si + 4]];
|
||||
break;
|
||||
}
|
||||
|
||||
while (fnames[sj] && fnames[sj++] != ',')
|
||||
;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
si += 32;
|
||||
} while (si);
|
||||
|
||||
} while (remap[rbuffer[0]]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flosskio_mapdir(const char * fnames, floss_blk * blks)
|
||||
{
|
||||
if (flosskio_open(18, 1))
|
||||
{
|
||||
mapdir(fnames, blks);
|
||||
|
||||
flosskio_close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool flossiec_mapdir(const char * fnames, floss_blk * blks)
|
||||
{
|
||||
if (flossiec_open(18, 1))
|
||||
{
|
||||
mapdir(fnames, blks);
|
||||
|
||||
flossiec_close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef FLOSSIEC_H
|
||||
#define FLOSSIEC_H
|
||||
|
||||
// When building you can use various defines to change the behaviour
|
||||
|
||||
// FLOSSIEC_BORDER=1 Enable border flashing while loading
|
||||
// FLOSSIEC_NODISPLAY=1 Disable the display while loading
|
||||
// FLOSSIEC_NOIRQ=1 Disable IRQ during load
|
||||
// FLOSSIEC_CODE=cseg Code segment to be used, when defined
|
||||
// FLOSSIEC_BSS=bseg BSS segment to be used, when defined
|
||||
|
||||
// Initialize the fastloader to be used without the kernal
|
||||
bool flossiec_init(char drive);
|
||||
|
||||
// Shutdown the fastloader when used without the kernal
|
||||
void flossiec_shutdown(void);
|
||||
|
||||
// Open a file for read with the fastloader without the kernal.
|
||||
// The file has to be read to completion before you can close
|
||||
// it again,
|
||||
bool flossiec_open(char track, char sector);
|
||||
|
||||
// Close a file after reading
|
||||
void flossiec_close(void);
|
||||
|
||||
|
||||
// Initialize the fastloader to be used with the kernal
|
||||
bool flosskio_init(char drive);
|
||||
|
||||
// Shutdown the fastloader when used with the kernal
|
||||
void flosskio_shutdown(void);
|
||||
|
||||
|
||||
// Open a file for read with the fastloader with the kernal
|
||||
// The file has to be read to completion before you can close
|
||||
// it again,
|
||||
bool flosskio_open(char track, char sector);
|
||||
|
||||
// Close a file after reading
|
||||
void flosskio_close(void);
|
||||
|
||||
|
||||
// Track and sector start of a file
|
||||
struct floss_blk
|
||||
{
|
||||
char track, sector;
|
||||
};
|
||||
|
||||
// Map a comma separated list of filenames to an array of
|
||||
// block start positions by reading the directory, using the
|
||||
// kernal.
|
||||
bool flosskio_mapdir(const char * fnames, floss_blk * blks);
|
||||
|
||||
// Map a comma separated list of filenames to an array of
|
||||
// block start positions by reading the directory, without the
|
||||
// kernal.
|
||||
bool flossiec_mapdir(const char * fnames, floss_blk * blks);
|
||||
|
||||
// Check for end of file while reading
|
||||
inline bool flossiec_eof(void);
|
||||
|
||||
// Get one char from uncompressed file
|
||||
inline char flossiec_get(void);
|
||||
|
||||
// Get one char from compressed file
|
||||
inline char flossiec_get_lzo(void);
|
||||
|
||||
// Read a section of a file into memory up to size bytes,
|
||||
// returns the first address after the read
|
||||
char * flossiec_read(char * dp, unsigned size);
|
||||
|
||||
// Read and expand section of a file into memory up to size
|
||||
// bytes, returns the first address after the read
|
||||
char * flossiec_read_lzo(char * dp, unsigned size);
|
||||
|
||||
|
||||
#pragma compile("flossiec.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,353 @@
|
||||
#include "iecbus.h"
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
|
||||
IEC_STATUS iec_status;
|
||||
char iec_queue;
|
||||
|
||||
#define CIA2B_ATNOUT 0x08
|
||||
#define CIA2B_CLKOUT 0x10
|
||||
#define CIA2B_DATAOUT 0x20
|
||||
|
||||
#define CIA2B_CLKIN 0x40
|
||||
#define CIA2B_DATAIN 0x80
|
||||
|
||||
#pragma optimize(push)
|
||||
#pragma optimize(1)
|
||||
|
||||
// multiples of 5us
|
||||
static void delay(char n)
|
||||
{
|
||||
__asm {
|
||||
ldx n
|
||||
l1:
|
||||
dex
|
||||
bne l1
|
||||
}
|
||||
}
|
||||
|
||||
static inline void data_true(void)
|
||||
{
|
||||
cia2.pra &= ~CIA2B_DATAOUT;
|
||||
}
|
||||
|
||||
static inline void data_false(void)
|
||||
{
|
||||
cia2.pra |= CIA2B_DATAOUT;
|
||||
}
|
||||
|
||||
static inline void clock_true(void)
|
||||
{
|
||||
cia2.pra &= ~CIA2B_CLKOUT;
|
||||
}
|
||||
|
||||
static inline void cdata_true(void)
|
||||
{
|
||||
cia2.pra &= ~(CIA2B_CLKOUT | CIA2B_DATAOUT);
|
||||
}
|
||||
|
||||
static inline void clock_false(void)
|
||||
{
|
||||
cia2.pra |= CIA2B_CLKOUT;
|
||||
}
|
||||
|
||||
static inline void atn_true(void)
|
||||
{
|
||||
cia2.pra &= ~CIA2B_ATNOUT;
|
||||
}
|
||||
|
||||
static inline void atn_false(void)
|
||||
{
|
||||
cia2.pra |= CIA2B_ATNOUT;
|
||||
}
|
||||
|
||||
static inline bool data_in(void)
|
||||
{
|
||||
return (cia2.pra & CIA2B_DATAIN) != 0;
|
||||
}
|
||||
|
||||
static inline bool clock_in(void)
|
||||
{
|
||||
return (cia2.pra & CIA2B_CLKIN) != 0;
|
||||
}
|
||||
|
||||
static bool data_check(void)
|
||||
{
|
||||
char cnt = 200;
|
||||
while (cnt > 0 && data_in())
|
||||
{
|
||||
delay(5);
|
||||
cnt--;
|
||||
}
|
||||
|
||||
if (cnt)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
iec_status = IEC_DATA_CHECK;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool iec_eoib(void)
|
||||
{
|
||||
clock_true();
|
||||
|
||||
while (!data_in());
|
||||
|
||||
delay(40);
|
||||
|
||||
return data_check();
|
||||
}
|
||||
|
||||
static void iec_writeb(char b)
|
||||
{
|
||||
clock_true();
|
||||
|
||||
while (!data_in());
|
||||
|
||||
delay(5);
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
clock_false();
|
||||
delay(5);
|
||||
if (b & 1)
|
||||
data_true();
|
||||
else
|
||||
data_false();
|
||||
clock_true();
|
||||
b >>= 1;
|
||||
delay(5);
|
||||
}
|
||||
clock_false();
|
||||
data_true();
|
||||
}
|
||||
|
||||
bool iec_write(char b)
|
||||
{
|
||||
if (iec_status == IEC_QUEUED)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
php
|
||||
sei
|
||||
}
|
||||
|
||||
iec_status = IEC_OK;
|
||||
iec_writeb(iec_queue);
|
||||
|
||||
__asm
|
||||
{
|
||||
plp
|
||||
}
|
||||
|
||||
data_check();
|
||||
}
|
||||
if (iec_status < IEC_ERROR)
|
||||
{
|
||||
iec_queue = b;
|
||||
iec_status = IEC_QUEUED;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char iec_read(void)
|
||||
{
|
||||
while (!clock_in());
|
||||
|
||||
__asm
|
||||
{
|
||||
php
|
||||
sei
|
||||
}
|
||||
|
||||
data_true();
|
||||
|
||||
char cnt = 100;
|
||||
while (cnt > 0 && clock_in())
|
||||
cnt--;
|
||||
|
||||
if (cnt == 0)
|
||||
{
|
||||
iec_status = IEC_EOF;
|
||||
data_false();
|
||||
delay(10);
|
||||
data_true();
|
||||
|
||||
cnt = 200;
|
||||
while (cnt > 0 && clock_in())
|
||||
cnt--;
|
||||
|
||||
if (cnt == 0)
|
||||
{
|
||||
iec_status = IEC_TIMEOUT;
|
||||
|
||||
__asm
|
||||
{
|
||||
plp
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char b = 0;
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
char c;
|
||||
while (!((c = cia2.pra) & CIA2B_CLKIN))
|
||||
;
|
||||
|
||||
b >>= 1;
|
||||
b |= c & 0x80;
|
||||
|
||||
while (cia2.pra & CIA2B_CLKIN)
|
||||
;
|
||||
}
|
||||
|
||||
data_false();
|
||||
|
||||
__asm
|
||||
{
|
||||
plp
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void iec_atn(char dev, char sec)
|
||||
{
|
||||
clock_true();
|
||||
data_true();
|
||||
atn_false();
|
||||
clock_false();
|
||||
|
||||
delay(200);
|
||||
|
||||
while (data_in());
|
||||
|
||||
iec_writeb(dev);
|
||||
data_check();
|
||||
if (sec != 0xff)
|
||||
{
|
||||
iec_writeb(sec);
|
||||
data_check();
|
||||
}
|
||||
|
||||
atn_true();
|
||||
}
|
||||
|
||||
|
||||
void iec_talk(char dev, char sec)
|
||||
{
|
||||
iec_status = IEC_OK;
|
||||
|
||||
iec_atn(dev | 0x40, sec | 0x60);
|
||||
data_false();
|
||||
|
||||
__asm
|
||||
{
|
||||
php
|
||||
sei
|
||||
}
|
||||
|
||||
clock_true();
|
||||
char cnt = 200;
|
||||
while (cnt > 0 && clock_in())
|
||||
cnt--;
|
||||
|
||||
__asm
|
||||
{
|
||||
plp
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void iec_untalk(void)
|
||||
{
|
||||
iec_atn(0x5f, 0xff);
|
||||
}
|
||||
|
||||
void iec_listen(char dev, char sec)
|
||||
{
|
||||
iec_status = IEC_OK;
|
||||
|
||||
iec_atn(dev | 0x20, sec | 0x60);
|
||||
}
|
||||
|
||||
void iec_unlisten(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
php
|
||||
sei
|
||||
}
|
||||
|
||||
if (iec_status == IEC_QUEUED)
|
||||
{
|
||||
iec_status = IEC_OK;
|
||||
iec_eoib();
|
||||
iec_writeb(iec_queue);
|
||||
data_check();
|
||||
}
|
||||
|
||||
iec_atn(0x3f, 0xff);
|
||||
clock_true();
|
||||
|
||||
__asm
|
||||
{
|
||||
plp
|
||||
}
|
||||
}
|
||||
|
||||
void iec_open(char dev, char sec, const char * fname)
|
||||
{
|
||||
iec_status = IEC_OK;
|
||||
|
||||
iec_atn(dev | 0x20, sec | 0xf0);
|
||||
|
||||
char i = 0;
|
||||
while (fname[i])
|
||||
{
|
||||
iec_write(fname[i]);
|
||||
i++;
|
||||
}
|
||||
iec_unlisten();
|
||||
}
|
||||
|
||||
void iec_close(char dev, char sec)
|
||||
{
|
||||
iec_atn(dev | 0x20, sec | 0xe0);
|
||||
iec_unlisten();
|
||||
}
|
||||
|
||||
int iec_write_bytes(const char * data, int num)
|
||||
{
|
||||
for(int i=0; i<num; i++)
|
||||
{
|
||||
if (!iec_write(data[i]))
|
||||
return i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int iec_read_bytes(char * data, int num)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < num)
|
||||
{
|
||||
char ch = iec_read();
|
||||
if (iec_status < IEC_ERROR)
|
||||
data[i++] = ch;
|
||||
if (iec_status != IEC_OK)
|
||||
return i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
#pragma optimize(pop)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef C64_IECBUS_H
|
||||
#define C64_IECBUS_H
|
||||
|
||||
enum IEC_STATUS
|
||||
{
|
||||
IEC_OK = 0x00,
|
||||
IEC_EOF = 0x01,
|
||||
IEC_QUEUED = 0x02,
|
||||
|
||||
IEC_ERROR = 0x80,
|
||||
IEC_TIMEOUT,
|
||||
IEC_DATA_CHECK,
|
||||
};
|
||||
|
||||
extern IEC_STATUS iec_status;
|
||||
|
||||
bool iec_write(char b);
|
||||
|
||||
char iec_read(void);
|
||||
|
||||
void iec_atn(char dev, char sec);
|
||||
|
||||
void iec_talk(char dev, char sec);
|
||||
|
||||
void iec_untalk(void);
|
||||
|
||||
void iec_listen(char dev, char sec);
|
||||
|
||||
void iec_unlisten(void);
|
||||
|
||||
void iec_open(char dev, char sec, const char * fname);
|
||||
|
||||
void iec_close(char dev, char sec);
|
||||
|
||||
int iec_write_bytes(const char * data, int num);
|
||||
|
||||
int iec_read_bytes(char * data, int num);
|
||||
|
||||
|
||||
#pragma compile("iecbus.c")
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "joystick.h"
|
||||
|
||||
sbyte joyx[2], joyy[2];
|
||||
bool joyb[2];
|
||||
|
||||
void joy_poll(char n)
|
||||
{
|
||||
char b = ((volatile char *)0xdc00)[n];
|
||||
|
||||
if (!(b & 1))
|
||||
joyy[n] = -1;
|
||||
else if (!(b & 2))
|
||||
joyy[n] = 1;
|
||||
else
|
||||
joyy[n] = 0;
|
||||
|
||||
if (!(b & 4))
|
||||
joyx[n] = -1;
|
||||
else if (!(b & 8))
|
||||
joyx[n] = 1;
|
||||
else
|
||||
joyx[n] = 0;
|
||||
|
||||
joyb[n] = (b & 0x10) == 0;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef C64_JOYSTICK_H
|
||||
#define C64_JOYSTICK_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern sbyte joyx[2], joyy[2];
|
||||
extern bool joyb[2];
|
||||
|
||||
// poll joystick input for joystick 0 or 1 and place
|
||||
// the x/y direction and the button status into the joyx/y/b
|
||||
// arrays for
|
||||
|
||||
void joy_poll(char n);
|
||||
|
||||
#pragma compile("joystick.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,541 @@
|
||||
#include "kernalio.h"
|
||||
|
||||
krnioerr krnio_pstatus[16];
|
||||
|
||||
#if defined(__C128__) || defined(__C128B__) || defined(__C128E__)
|
||||
void krnio_setbnk(char filebank, char namebank)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
lda filebank
|
||||
ldx namebank
|
||||
jsr $ff68 // setbnk
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(krnio_setbnk)
|
||||
#endif
|
||||
|
||||
#if defined(__PLUS4__)
|
||||
#pragma code(lowcode)
|
||||
#define BANKIN sta 0xff3e
|
||||
#define BANKOUT sta 0xff3f
|
||||
#define BANKINLINE __noinline
|
||||
#else
|
||||
#define BANKIN
|
||||
#define BANKOUT
|
||||
#define BANKINLINE
|
||||
#endif
|
||||
|
||||
#if defined(__CBMPET__)
|
||||
#define FNLEN 0xD1 // Length of filename
|
||||
#define LFN 0xD2 // Current Logical File Number
|
||||
#define SECADR 0xD3 // Secondary address
|
||||
#define DEVNUM 0xD4 // Device number
|
||||
#define FNADR 0xDA // Pointer to file name
|
||||
#define ST 0x96 // IEC status byte
|
||||
|
||||
// PET ROM Detection
|
||||
#define PET_DETECT 0xFFFB // Distinction V2 vs V4 BASIC
|
||||
#define PET_2000 0xCA
|
||||
#define PET_3000 0xFC
|
||||
#define PET_4000 0xFD
|
||||
|
||||
__asm k_checkst
|
||||
{
|
||||
lda ST
|
||||
beq l1
|
||||
lda #5 // Device not present
|
||||
sec
|
||||
rts
|
||||
l1:
|
||||
clc
|
||||
rts
|
||||
}
|
||||
|
||||
__asm k_setlfs
|
||||
{
|
||||
sta LFN // setlfs replacement
|
||||
stx DEVNUM
|
||||
sty SECADR
|
||||
rts
|
||||
}
|
||||
|
||||
__asm k_open
|
||||
{
|
||||
lda PET_DETECT
|
||||
cmp #PET_4000
|
||||
bne V2
|
||||
jsr $f563
|
||||
jmp k_checkst
|
||||
V2:
|
||||
jsr $f524
|
||||
jmp k_checkst
|
||||
}
|
||||
|
||||
__asm k_close
|
||||
{
|
||||
ldx PET_DETECT
|
||||
cpx #PET_4000
|
||||
bne l1
|
||||
jmp $F2E2 // BASIC 4
|
||||
l1:
|
||||
jmp $F2AE //BASIC 2&3
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BANKINLINE void krnio_setnam(const char * name)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
lda name
|
||||
ora name + 1
|
||||
beq W1
|
||||
|
||||
ldy #$ff
|
||||
L1: iny
|
||||
lda (name), y
|
||||
bne L1
|
||||
tya
|
||||
W1: ldx name
|
||||
ldy name + 1
|
||||
BANKIN
|
||||
#if defined(__CBMPET__)
|
||||
sta FNLEN
|
||||
stx FNADR
|
||||
sty FNADR+1
|
||||
#else
|
||||
jsr $ffbd // setnam
|
||||
#endif
|
||||
BANKOUT
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(krnio_setnam)
|
||||
|
||||
BANKINLINE void krnio_setnam_n(const char * name, char len)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
lda len
|
||||
ldx name
|
||||
ldy name + 1
|
||||
BANKIN
|
||||
#if defined(__CBMPET__)
|
||||
sta FNLEN
|
||||
stx FNADR
|
||||
sty FNADR+1
|
||||
#else
|
||||
jsr $ffbd // setnam
|
||||
#endif
|
||||
BANKOUT
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(krnio_setnam_n)
|
||||
|
||||
BANKINLINE bool krnio_open(char fnum, char device, char channel)
|
||||
{
|
||||
krnio_pstatus[fnum] = KRNIO_OK;
|
||||
|
||||
return char(__asm
|
||||
{
|
||||
lda #0
|
||||
sta accu
|
||||
sta accu + 1
|
||||
|
||||
BANKIN
|
||||
|
||||
lda fnum
|
||||
ldx device
|
||||
ldy channel
|
||||
#if defined(__CBMPET__)
|
||||
jsr k_setlfs
|
||||
|
||||
jsr k_open
|
||||
#else
|
||||
jsr $ffba // setlfs
|
||||
|
||||
jsr $ffc0 // open
|
||||
#endif
|
||||
bcc W1
|
||||
|
||||
lda fnum
|
||||
#if defined(__CBMPET__)
|
||||
jsr k_close
|
||||
#else
|
||||
jsr $ffc3 // close
|
||||
#endif
|
||||
jmp E2
|
||||
W1:
|
||||
lda #1
|
||||
sta accu
|
||||
|
||||
BANKOUT
|
||||
E2:
|
||||
});
|
||||
}
|
||||
|
||||
#pragma native(krnio_open)
|
||||
|
||||
BANKINLINE void krnio_close(char fnum)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
BANKIN
|
||||
lda fnum
|
||||
#if defined(__CBMPET__)
|
||||
jsr k_close
|
||||
#else
|
||||
jsr $ffc3 // close
|
||||
#endif
|
||||
BANKOUT
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(krnio_close)
|
||||
|
||||
BANKINLINE krnioerr krnio_status(void)
|
||||
{
|
||||
return __asm
|
||||
{
|
||||
#if defined(__CBMPET__)
|
||||
lda ST
|
||||
#else
|
||||
BANKIN
|
||||
jsr $ffb7 : ->a // readst
|
||||
BANKOUT
|
||||
#endif
|
||||
sta accu
|
||||
lda #0
|
||||
sta accu + 1
|
||||
};
|
||||
}
|
||||
|
||||
#pragma native(krnio_status)
|
||||
|
||||
|
||||
BANKINLINE bool krnio_load(char fnum, char device, char channel)
|
||||
{
|
||||
return char(__asm
|
||||
{
|
||||
BANKIN
|
||||
lda fnum
|
||||
ldx device
|
||||
ldy channel
|
||||
jsr $ffba // setlfs
|
||||
|
||||
lda #0
|
||||
ldx #0
|
||||
ldy #0
|
||||
jsr $FFD5 // load
|
||||
BANKOUT
|
||||
|
||||
lda #0
|
||||
rol
|
||||
eor #1
|
||||
sta accu
|
||||
});
|
||||
}
|
||||
|
||||
#pragma native(krnio_load)
|
||||
|
||||
BANKINLINE bool krnio_save(char device, const char* start, const char* end)
|
||||
{
|
||||
return char(__asm
|
||||
{
|
||||
BANKIN
|
||||
lda #0
|
||||
ldx device
|
||||
ldy #0
|
||||
jsr $ffba // setlfs
|
||||
|
||||
lda #start
|
||||
ldx end
|
||||
ldy end+1
|
||||
jsr $FFD8 // save
|
||||
|
||||
BANKOUT
|
||||
|
||||
lda #0
|
||||
rol
|
||||
eor #1
|
||||
sta accu
|
||||
});
|
||||
}
|
||||
|
||||
#pragma native(krnio_save)
|
||||
|
||||
BANKINLINE bool krnio_chkout(char fnum)
|
||||
{
|
||||
return char(__asm
|
||||
{
|
||||
BANKIN
|
||||
ldx fnum
|
||||
jsr $ffc9 : x->ax // chkout
|
||||
#if defined(__CBMPET__)
|
||||
jsr k_checkst
|
||||
#endif
|
||||
BANKOUT
|
||||
|
||||
lda #0
|
||||
rol
|
||||
eor #1
|
||||
sta accu
|
||||
});
|
||||
}
|
||||
|
||||
#pragma native(krnio_chkout)
|
||||
|
||||
BANKINLINE bool krnio_chkin(char fnum)
|
||||
{
|
||||
return char(__asm
|
||||
{
|
||||
BANKIN
|
||||
ldx fnum
|
||||
jsr $ffc6 : x->axy // chkin
|
||||
#if defined(__CBMPET__)
|
||||
jsr k_checkst
|
||||
#endif
|
||||
BANKOUT
|
||||
|
||||
lda #0
|
||||
rol
|
||||
eor #1
|
||||
sta accu
|
||||
});
|
||||
}
|
||||
|
||||
#pragma native(krnio_chkin)
|
||||
|
||||
BANKINLINE void krnio_clrchn(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
BANKIN
|
||||
jsr $ffcc : ->ax // clrchn
|
||||
BANKOUT
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(krnio_clrchn)
|
||||
|
||||
BANKINLINE bool krnio_chrout(char ch)
|
||||
{
|
||||
return char(__asm
|
||||
{
|
||||
BANKIN
|
||||
lda ch
|
||||
jsr $ffd2 : a->a // chrout
|
||||
sta accu
|
||||
BANKOUT
|
||||
});
|
||||
}
|
||||
|
||||
#pragma native(krnio_chrout)
|
||||
|
||||
BANKINLINE char krnio_chrin(void)
|
||||
{
|
||||
return __asm
|
||||
{
|
||||
BANKIN
|
||||
jsr $ffcf : a->a // chrin
|
||||
sta accu
|
||||
BANKOUT
|
||||
};
|
||||
}
|
||||
|
||||
#pragma native(krnio_chrin)
|
||||
|
||||
#if defined(__PLUS4__)
|
||||
#pragma code(code)
|
||||
#endif
|
||||
|
||||
int krnio_getch(char fnum)
|
||||
{
|
||||
if (krnio_pstatus[fnum] == KRNIO_EOF)
|
||||
return -1;
|
||||
|
||||
int ch = -1;
|
||||
if (krnio_chkin(fnum))
|
||||
{
|
||||
ch = krnio_chrin();
|
||||
krnioerr err = krnio_status();
|
||||
krnio_pstatus[fnum] = err;
|
||||
if (err)
|
||||
{
|
||||
if (err == KRNIO_EOF)
|
||||
ch |= 0x100;
|
||||
else
|
||||
ch = -1;
|
||||
}
|
||||
}
|
||||
krnio_clrchn();
|
||||
return ch;
|
||||
}
|
||||
|
||||
int krnio_putch(char fnum, char ch)
|
||||
{
|
||||
if (krnio_chkout(fnum))
|
||||
{
|
||||
krnio_chrout(ch);
|
||||
krnio_clrchn();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int krnio_puts(char fnum, const char * data)
|
||||
{
|
||||
if (krnio_chkout(fnum))
|
||||
{
|
||||
int i = 0;
|
||||
while (data[i])
|
||||
krnio_chrout(data[i++]);
|
||||
krnio_clrchn();
|
||||
return i;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#pragma native(krnio_puts)
|
||||
|
||||
int krnio_write(char fnum, const char * data, int num)
|
||||
{
|
||||
if (krnio_chkout(fnum))
|
||||
{
|
||||
for(int i=0; i<num; i++)
|
||||
krnio_chrout(data[i]);
|
||||
krnio_clrchn();
|
||||
return num;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#pragma native(krnio_write)
|
||||
|
||||
int krnio_read(char fnum, char * data, int num)
|
||||
{
|
||||
if (krnio_pstatus[fnum] == KRNIO_EOF)
|
||||
return 0;
|
||||
|
||||
if (krnio_chkin(fnum))
|
||||
{
|
||||
int i = 0;
|
||||
int ch;
|
||||
while (i < num)
|
||||
{
|
||||
ch = krnio_chrin();
|
||||
krnioerr err = krnio_status();
|
||||
krnio_pstatus[fnum] = err;
|
||||
if (err && err != KRNIO_EOF)
|
||||
break;
|
||||
data[i++] = (char)ch;
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
krnio_clrchn();
|
||||
return i;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#pragma native(krnio_read)
|
||||
|
||||
int krnio_read_lzo(char fnum, char * data)
|
||||
{
|
||||
if (krnio_pstatus[fnum] == KRNIO_EOF)
|
||||
return 0;
|
||||
|
||||
if (krnio_chkin(fnum))
|
||||
{
|
||||
int i = 0;
|
||||
char ch;
|
||||
char cmd = 0;
|
||||
krnioerr err;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
ch = krnio_chrin();
|
||||
err = krnio_status();
|
||||
if (err && err != KRNIO_EOF)
|
||||
break;
|
||||
|
||||
if (cmd & 0x80)
|
||||
{
|
||||
|
||||
char * dp = data + i, * cp = dp - ch;
|
||||
|
||||
cmd &= 0x7f;
|
||||
i += cmd;
|
||||
|
||||
char n = 0x00;
|
||||
do {
|
||||
dp[n] = cp[n];
|
||||
n++;
|
||||
} while (n != cmd);
|
||||
cmd = 0;
|
||||
}
|
||||
else if (cmd)
|
||||
{
|
||||
data[i++] = (char)ch;
|
||||
cmd--;
|
||||
}
|
||||
else if (ch)
|
||||
cmd = ch;
|
||||
else
|
||||
break;
|
||||
|
||||
if (err)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
krnio_pstatus[fnum] = err;
|
||||
|
||||
krnio_clrchn();
|
||||
return i;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#pragma native(krnio_read_lzo)
|
||||
|
||||
int krnio_gets(char fnum, char * data, int num)
|
||||
{
|
||||
if (krnio_pstatus[fnum] == KRNIO_EOF)
|
||||
return 0;
|
||||
|
||||
if (krnio_chkin(fnum))
|
||||
{
|
||||
krnioerr err = KRNIO_OK;
|
||||
int i = 0;
|
||||
int ch;
|
||||
while (i + 1 < num)
|
||||
{
|
||||
ch = krnio_chrin();
|
||||
err = krnio_status();
|
||||
if (err && err != KRNIO_EOF)
|
||||
break;
|
||||
data[i++] = (char)ch;
|
||||
if (ch == 13 || ch == 10 || err)
|
||||
break;
|
||||
}
|
||||
krnio_pstatus[fnum] = err;
|
||||
data[i] = 0;
|
||||
krnio_clrchn();
|
||||
return i;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
#pragma native(krnio_gets)
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef C64_KERNALIO_H
|
||||
#define C64_KERNALIO_H
|
||||
|
||||
// Error and status codes returned by krnio_status
|
||||
|
||||
enum krnioerr
|
||||
{
|
||||
KRNIO_OK = 0,
|
||||
KRNIO_DIR = 0x01,
|
||||
KRNIO_TIMEOUT = 0x02,
|
||||
KRNIO_SHORT = 0x04,
|
||||
KRNIO_LONG = 0x08,
|
||||
KRNIO_VERIFY = 0x10,
|
||||
KRNIO_CHKSUM = 0x20,
|
||||
KRNIO_EOF = 0x40,
|
||||
KRNIO_NODEVICE = 0x80
|
||||
};
|
||||
|
||||
extern krnioerr krnio_pstatus[16];
|
||||
|
||||
#if defined(__C128__) || defined(__C128B__) || defined(__C128E__)
|
||||
// C128: Set bank for load/save and filename for next file operations
|
||||
void krnio_setbnk(char filebank, char namebank);
|
||||
#endif
|
||||
|
||||
// Set filename for next krnio_open operation, make sure
|
||||
// that the string is still valid when calling krnio_open
|
||||
|
||||
void krnio_setnam(const char * name);
|
||||
|
||||
void krnio_setnam_n(const char * name, char len);
|
||||
|
||||
// open a kernal file/stream/io channel, returns true on success
|
||||
|
||||
bool krnio_open(char fnum, char device, char channel);
|
||||
|
||||
// close a kernal file/stream/io channel
|
||||
|
||||
void krnio_close(char fnum);
|
||||
|
||||
// get the error / status of the last io operation
|
||||
|
||||
krnioerr krnio_status(void);
|
||||
|
||||
bool krnio_load(char fnum, char device, char channel);
|
||||
|
||||
bool krnio_save(char device, const char* start, const char* end);
|
||||
|
||||
// select the given file for stream output
|
||||
|
||||
bool krnio_chkout(char fnum);
|
||||
|
||||
// select the given file for stream input
|
||||
|
||||
bool krnio_chkin(char fnum);
|
||||
|
||||
// clear input and output file selection
|
||||
|
||||
void krnio_clrchn(void);
|
||||
|
||||
// write a single byte to the current output channel
|
||||
|
||||
bool krnio_chrout(char ch);
|
||||
|
||||
// read a single byte from the current input channel
|
||||
|
||||
char krnio_chrin(void);
|
||||
|
||||
// read a single byte from the given file/channel, returns
|
||||
// a negative result on failure. If this was the last byte
|
||||
// the bit #8 (0x0100) will be set in the return value
|
||||
|
||||
int krnio_getch(char fnum);
|
||||
|
||||
// write a single byte to the given file/channel, returns
|
||||
// a negative value on failure.
|
||||
|
||||
int krnio_putch(char fnum, char ch);
|
||||
|
||||
// write an array of bytes to the given file/channel
|
||||
|
||||
int krnio_write(char fnum, const char * data, int num);
|
||||
|
||||
// write a zero terminated string to the given file/channel
|
||||
|
||||
int krnio_puts(char fnum, const char * data);
|
||||
|
||||
// read an array of bytes from the given file, returns the number
|
||||
// of bytes read, or a negative number on failure
|
||||
|
||||
int krnio_read(char fnum, char * data, int num);
|
||||
|
||||
int krnio_read_lzo(char fnum, char * data);
|
||||
|
||||
// read a line from the given file, terminated by a CR or LF character
|
||||
// and appends a zero byte.
|
||||
|
||||
int krnio_gets(char fnum, char * data, int num);
|
||||
|
||||
#pragma compile("kernalio.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "keyboard.h"
|
||||
#include "cia.h"
|
||||
|
||||
const char keyb_codes[128] = {
|
||||
KEY_DEL, KEY_RETURN, KEY_CSR_RIGHT, KEY_F7, KEY_F1, KEY_F3, KEY_F5, KEY_CSR_DOWN,
|
||||
'3', 'w', 'a', '4', 'z', 's', 'e', 0,
|
||||
'5', 'r', 'd', '6', 'c', 'f', 't', 'x',
|
||||
'7', 'y', 'g', '8', 'b', 'h', 'u', 'v',
|
||||
'9', 'i', 'j', '0', 'm', 'k', 'o', 'n',
|
||||
'+', 'p', 'l', '-', '.', ':', '@', ',',
|
||||
0 , '*', ';', KEY_HOME, 0, '=', '^', '/',
|
||||
'1', KEY_ARROW_LEFT, 0, '2', ' ', 0, 'q', KEY_ESC,
|
||||
|
||||
KEY_INST, KEY_RETURN, KEY_CSR_LEFT, KEY_F8, KEY_F2, KEY_F4, KEY_F6, KEY_CSR_UP,
|
||||
'#', 'W', 'A', '$', 'Z', 'S', 'E', 0,
|
||||
'%', 'R', 'D', '&', 'C', 'F', 'T', 'X',
|
||||
'\'', 'Y', 'G', '(', 'B', 'H', 'U', 'V',
|
||||
')', 'I', 'J', '0', 'M', 'K', 'O', 'N',
|
||||
0, 'P', 'L', 0, '>', '[', '@', '<',
|
||||
0, 0, ']', KEY_CLR, 0, 0, '^', '?',
|
||||
'!', 0, 0, '"', ' ', 0, 'Q', KEY_ESC,
|
||||
|
||||
};
|
||||
|
||||
|
||||
byte keyb_matrix[8];
|
||||
|
||||
KeyScanCode keyb_key;
|
||||
static byte keyb_pmatrix[8];
|
||||
|
||||
bool key_pressed(KeyScanCode code)
|
||||
{
|
||||
return !(keyb_matrix[code >> 3] & (1 << (code & 7)));
|
||||
}
|
||||
|
||||
bool key_shift(void)
|
||||
{
|
||||
return
|
||||
!(keyb_matrix[6] & 0x10) ||
|
||||
!(keyb_matrix[1] & 0x80);
|
||||
}
|
||||
|
||||
void keyb_poll(void)
|
||||
{
|
||||
cia1.ddra = 0xff;
|
||||
cia1.pra = 0xff;
|
||||
keyb_key = 0x00;
|
||||
|
||||
if (cia1.prb == 0xff)
|
||||
{
|
||||
cia1.ddrb = 0x00;
|
||||
cia1.pra = 0x00;
|
||||
|
||||
if (cia1.prb != 0xff)
|
||||
{
|
||||
keyb_matrix[6] &= 0xef;
|
||||
keyb_matrix[1] &= 0x7f;
|
||||
|
||||
byte a = 0xfe;
|
||||
for(byte i=0; i<8; i++)
|
||||
{
|
||||
cia1.pra = a;
|
||||
a = (a << 1) | 1;
|
||||
|
||||
byte p = keyb_matrix[i];
|
||||
byte k = cia1.prb;
|
||||
keyb_matrix[i] = k;
|
||||
|
||||
k = (k ^ 0xff) & p;
|
||||
if (k)
|
||||
{
|
||||
byte j = 8 * i | 0x80;
|
||||
if (k & 0xf0)
|
||||
j += 4;
|
||||
if (k & 0xcc)
|
||||
j += 2;
|
||||
if (k & 0xaa)
|
||||
j++;
|
||||
keyb_key = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyb_key && (!(keyb_matrix[1] & 0x80) || (!(keyb_matrix[6] & 0x10))))
|
||||
keyb_key |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyb_matrix[0] = 0xff;
|
||||
keyb_matrix[1] = 0xff;
|
||||
keyb_matrix[2] = 0xff;
|
||||
keyb_matrix[3] = 0xff;
|
||||
keyb_matrix[4] = 0xff;
|
||||
keyb_matrix[5] = 0xff;
|
||||
keyb_matrix[6] = 0xff;
|
||||
keyb_matrix[7] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
cia1.pra = ciaa_pra_def;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#ifndef C64_KEYBOARD_H
|
||||
#define C64_KEYBOARD_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define KEY_CSR_DOWN (17)
|
||||
#define KEY_CSR_RIGHT (29)
|
||||
#define KEY_CSR_UP (17 + 128)
|
||||
#define KEY_CSR_LEFT (29 + 128)
|
||||
|
||||
#define KEY_ARROW_LEFT (95)
|
||||
|
||||
#define KEY_ESC (27)
|
||||
#define KEY_DEL (20)
|
||||
#define KEY_INST (148)
|
||||
#define KEY_RETURN (13)
|
||||
|
||||
#define KEY_HOME (19)
|
||||
#define KEY_CLR (147)
|
||||
|
||||
#define KEY_F1 (133)
|
||||
#define KEY_F3 (134)
|
||||
#define KEY_F5 (135)
|
||||
#define KEY_F7 (136)
|
||||
|
||||
#define KEY_F2 (137)
|
||||
#define KEY_F4 (138)
|
||||
#define KEY_F6 (139)
|
||||
#define KEY_F8 (140)
|
||||
|
||||
enum KeyScanCode
|
||||
{
|
||||
KSCAN_DEL,
|
||||
KSCAN_RETURN,
|
||||
KSCAN_CSR_RIGHT,
|
||||
KSCAN_F7,
|
||||
KSCAN_F1,
|
||||
KSCAN_F3,
|
||||
KSCAN_F5,
|
||||
KSCAN_CSR_DOWN,
|
||||
|
||||
KSCAN_3,
|
||||
KSCAN_W,
|
||||
KSCAN_A,
|
||||
KSCAN_4,
|
||||
KSCAN_Z,
|
||||
KSCAN_S,
|
||||
KSCAN_E,
|
||||
KSCAN_SHIFT_LOCK,
|
||||
|
||||
KSCAN_5,
|
||||
KSCAN_R,
|
||||
KSCAN_D,
|
||||
KSCAN_6,
|
||||
KSCAN_C,
|
||||
KSCAN_F,
|
||||
KSCAN_T,
|
||||
KSCAN_X,
|
||||
|
||||
KSCAN_7,
|
||||
KSCAN_Y,
|
||||
KSCAN_G,
|
||||
KSCAN_8,
|
||||
KSCAN_B,
|
||||
KSCAN_H,
|
||||
KSCAN_U,
|
||||
KSCAN_V,
|
||||
|
||||
KSCAN_9,
|
||||
KSCAN_I,
|
||||
KSCAN_J,
|
||||
KSCAN_0,
|
||||
KSCAN_M,
|
||||
KSCAN_K,
|
||||
KSCAN_O,
|
||||
KSCAN_N,
|
||||
|
||||
KSCAN_PLUS,
|
||||
KSCAN_P,
|
||||
KSCAN_L,
|
||||
KSCAN_MINUS,
|
||||
KSCAN_DOT,
|
||||
KSCAN_COLON,
|
||||
KSCAN_AT,
|
||||
KSCAN_COMMA,
|
||||
|
||||
KSCAN_POUND,
|
||||
KSCAN_STAR,
|
||||
KSCAN_SEMICOLON,
|
||||
KSCAN_HOME,
|
||||
KSCAN_RSHIFT,
|
||||
KSCAN_EQUAL,
|
||||
KSCAN_ARROW_UP,
|
||||
KSCAN_SLASH,
|
||||
|
||||
KSCAN_1,
|
||||
KSCAN_ARROW_LEFT,
|
||||
KSCAN_CONTROL,
|
||||
KSCAN_2,
|
||||
KSCAN_SPACE,
|
||||
KSCAN_COMMODORE,
|
||||
KSCAN_Q,
|
||||
KSCAN_STOP,
|
||||
|
||||
KSCAN_QUAL_SHIFT = 0x40,
|
||||
KSCAN_QUAL_MASK = 0x7f,
|
||||
KSCAN_QUAL_DOWN = 0x80,
|
||||
|
||||
KSCAN_MAX = 0xff
|
||||
};
|
||||
|
||||
// map of keyboard codes to PETSCII, first 64 without shift
|
||||
// second 64 with shift
|
||||
|
||||
extern const char keyb_codes[128];
|
||||
|
||||
// current status of key matrix
|
||||
extern byte keyb_matrix[8];
|
||||
|
||||
// current key in scan code - the top level bit KSCAN_QUAL_DOWN is
|
||||
// used to indicate a key is pressed, so 0 is no key
|
||||
extern KeyScanCode keyb_key;
|
||||
|
||||
// poll keyboard matrix
|
||||
|
||||
void keyb_poll(void);
|
||||
|
||||
inline bool key_pressed(KeyScanCode code);
|
||||
|
||||
inline bool key_shift(void);
|
||||
|
||||
#pragma compile("keyboard.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
// This code is meant to keep the C64 running while the program it is part of banks
|
||||
// out the BASIC or Kernal ROM to have RAM available. If an IRQ or NMI occurs during
|
||||
// that time and a ROM routine is called that isn't there, the C64 will crash.
|
||||
// This code replaces the IRQ and NMI handling code to bank the BASIC and Kernal ROMs
|
||||
// back in, call the original handling routines, and then restore the situation as it
|
||||
// was when the interrupt happened.
|
||||
|
||||
#include "memmap.h"
|
||||
|
||||
__asm DoneTrampoline
|
||||
{
|
||||
stx $01 // The ROM code at jmp ($fffa) has saved our X value
|
||||
// so we can restore it to $01. Our banks our back to whatever it was
|
||||
pla // now we pull X and A and restore them
|
||||
tax
|
||||
pla
|
||||
rti // RTI can now pull the original status byte and return address and
|
||||
// return to the original code.
|
||||
}
|
||||
|
||||
__asm IRQTrampoline
|
||||
{
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
|
||||
lda #>DoneTrampoline
|
||||
pha
|
||||
lda #<DoneTrampoline
|
||||
pha
|
||||
tsx
|
||||
lda $0105, x
|
||||
pha
|
||||
ldx $01
|
||||
lda #$36
|
||||
sta $01
|
||||
jmp ($fffe)
|
||||
}
|
||||
|
||||
__asm NMITrampoline
|
||||
{
|
||||
// NMI just happend, so stack contains ($01ff for example):
|
||||
// $01ff High byte of return address
|
||||
// $01fe Low byte of return address
|
||||
// $01fd status flag byte
|
||||
|
||||
pha // $01fc save A on the stack
|
||||
txa
|
||||
pha // $01fb save X on the stack
|
||||
|
||||
lda #>DoneTrampoline // $01fa save the high byte of DoneTrampoline()
|
||||
pha
|
||||
lda #<DoneTrampoline // $01f9 save the low byte of DoneTrampoline()
|
||||
pha
|
||||
tsx // transfer the SP ($f8) to X
|
||||
lda $0105, x // $0105 + $f8 = $01fd (we have virtually shifted the end of stack
|
||||
// to $0105 to get to the original status flag)
|
||||
pha // and we push it again
|
||||
ldx $01 // Now we save the current $01 value so we can restore it later
|
||||
lda #$36 // set $01 to its default value (bank ROMs back in)
|
||||
sta $01
|
||||
jmp ($fffa) // call the original handler (we are looking at ROM now, not RAM)
|
||||
// this routine saves A, X and Y and ends in an RTI
|
||||
// that will pop SP and the DoneTrampoline() address and jump to it
|
||||
}
|
||||
|
||||
void mmap_trampoline(void)
|
||||
{
|
||||
// This is to set the IRQ and NMI handler hooks to our own code.
|
||||
// But note, that his is written to and saved in RAM under ROM at $fffa/$fffb and $fffe/$ffff
|
||||
*((void **)0xfffa) = NMITrampoline;
|
||||
*((void **)0xfffe) = IRQTrampoline;
|
||||
}
|
||||
|
||||
#pragma native(mmap_trampoline)
|
||||
|
||||
char mmap_set(char pla)
|
||||
{
|
||||
char ppla = *((char *)0x01);
|
||||
*((volatile __memmap char *)0x01) = pla;
|
||||
return ppla;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef MEMMAP_H
|
||||
#define MEMMAP_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// MMAP_ROM : BASIC + I/O + KERNAL -> default power on config
|
||||
// MMAP_NO_BASIC : I/O + KERNAL -> easy extra chunk of contiguous RAM
|
||||
// MMAP_NO_ROM : I/O -> I/O and COLOR RAM in $d000-$dfff block, rest is RAM
|
||||
// MMAP_RAM : -> ALL RAM, you'll need to manage some state switching...
|
||||
// MMAP_CHAR_ROM : CHAR -> no BASIC or KERNAL or I/O, but can copy CHAR ROM
|
||||
// MMAP_ALL_ROM : BASIC + CHAR + KERNAL -> All ROM functions available, but no I/O
|
||||
|
||||
#define MMAP_ROM 0x37
|
||||
#define MMAP_NO_BASIC 0x36
|
||||
#define MMAP_NO_ROM 0x35
|
||||
#define MMAP_RAM 0x30
|
||||
#define MMAP_CHAR_ROM 0x31
|
||||
#define MMAP_ALL_ROM 0x33
|
||||
|
||||
// Install an IRQ an NMI trampoline, that routes the kernal interrupts
|
||||
// through an intermediate trampoline when the kernal ROM is not paged
|
||||
// in. The trampoline enables the ROM, executes the interrupt and
|
||||
// restores the memory map setting before returning.
|
||||
|
||||
void mmap_trampoline(void);
|
||||
|
||||
// Set the memory map in a way that is compatible with the IRQ
|
||||
// trampoline, returns the previous state
|
||||
|
||||
inline char mmap_set(char pla);
|
||||
|
||||
#pragma compile("memmap.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "mouse.h"
|
||||
#include "sid.h"
|
||||
#include "cia.h"
|
||||
|
||||
sbyte mouse_dx, mouse_dy;
|
||||
bool mouse_lb, mouse_rb;
|
||||
static char mouse_px, mouse_py;
|
||||
static char mouse_port;
|
||||
|
||||
inline signed char dpos(char * old, char mnew)
|
||||
{
|
||||
mnew = (mnew & 0x7f) >> 1;
|
||||
|
||||
char diff = (mnew - *old) & 0x3f;
|
||||
|
||||
if (diff >= 0x20)
|
||||
{
|
||||
*old = mnew;
|
||||
return diff | 0xe0;
|
||||
}
|
||||
else if (diff)
|
||||
{
|
||||
*old = mnew;
|
||||
return diff;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mouse_poll(void)
|
||||
{
|
||||
char b = ((volatile char *)0xdc00)[mouse_port];
|
||||
mouse_rb = (b & 0x01) == 0;
|
||||
mouse_lb = (b & 0x10) == 0;
|
||||
|
||||
char x = sid.potx, y = sid.poty;
|
||||
|
||||
mouse_dx = dpos(&mouse_px, x);
|
||||
mouse_dy = dpos(&mouse_py, y);
|
||||
}
|
||||
|
||||
void mouse_arm(char n)
|
||||
{
|
||||
mouse_port = n;
|
||||
cia1.pra = ciaa_pra_def = n ? 0x7f : 0xbf;
|
||||
}
|
||||
|
||||
void mouse_init(void)
|
||||
{
|
||||
mouse_arm(1);
|
||||
mouse_poll();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef C64_MOUSE_H
|
||||
#define C64_MOUSE_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
extern sbyte mouse_dx, mouse_dy;
|
||||
extern bool mouse_lb, mouse_rb;
|
||||
|
||||
|
||||
void mouse_init(void);
|
||||
|
||||
// arm the potentiometer input for the selected mouse input
|
||||
// needs ~4ms to stabilize
|
||||
|
||||
void mouse_arm(char n);
|
||||
|
||||
// poll mouse input for selected mouse, but the relative
|
||||
// movement into mouse_dx/dy and the button state into
|
||||
// mouse_lb/mouse_rb
|
||||
|
||||
void mouse_poll(void);
|
||||
|
||||
#pragma compile("mouse.c")
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,716 @@
|
||||
#include "rasterirq.h"
|
||||
|
||||
#include <c64/vic.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/asm6502.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
volatile byte rirq_count;
|
||||
static byte rirq_pcount;
|
||||
|
||||
byte rasterIRQRows[NUM_IRQS + 1];
|
||||
byte rasterIRQIndex[NUM_IRQS + 1]; // Sort order of interrupt index, offset by one
|
||||
#ifdef ZPAGE_IRQS
|
||||
__zeropage
|
||||
#endif
|
||||
byte rasterIRQNext[NUM_IRQS + 1]; // Rasterline of interrupt, terminated by 0xff
|
||||
byte rasterIRQLow[NUM_IRQS]; // Address of interrupt code
|
||||
byte rasterIRQHigh[NUM_IRQS];
|
||||
|
||||
#ifdef ZPAGE_IRQS
|
||||
__zeropage
|
||||
#endif
|
||||
volatile byte nextIRQ;
|
||||
|
||||
// nextIRQ is the index of the next expected IRQ, or $ff if no IRQ is scheduled
|
||||
|
||||
__asm rirq_isr_ram_io
|
||||
{
|
||||
stx plrx + 1
|
||||
|
||||
ldx nextIRQ
|
||||
bmi exi
|
||||
|
||||
sta plra + 1
|
||||
sty plry + 1
|
||||
|
||||
l1:
|
||||
lda rasterIRQNext, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
ldx rasterIRQLow, y
|
||||
stx ji + 1
|
||||
ldx rasterIRQHigh, y
|
||||
stx ji + 2
|
||||
|
||||
ji:
|
||||
jsr $0000
|
||||
|
||||
inc nextIRQ
|
||||
ldx nextIRQ
|
||||
|
||||
ldy rasterIRQNext, x
|
||||
|
||||
asl $d019
|
||||
|
||||
cpy #$ff
|
||||
beq e2
|
||||
|
||||
dey
|
||||
sty $d012
|
||||
dey
|
||||
cpy $d012
|
||||
bcc l1
|
||||
|
||||
plry:
|
||||
ldy #0
|
||||
plra:
|
||||
lda #0
|
||||
plrx:
|
||||
ldx #0
|
||||
rti
|
||||
|
||||
exi:
|
||||
asl $d019
|
||||
jmp plrx
|
||||
|
||||
// No more interrupts to service
|
||||
e2:
|
||||
inc rirq_count
|
||||
|
||||
ldy rasterIRQNext
|
||||
dey
|
||||
sty $d012
|
||||
ldx #0
|
||||
stx nextIRQ
|
||||
beq plry
|
||||
}
|
||||
|
||||
__asm rirq_isr_io
|
||||
{
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
kentry:
|
||||
|
||||
ldx nextIRQ
|
||||
bmi exi
|
||||
l1:
|
||||
lda rasterIRQNext, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
ldx rasterIRQLow, y
|
||||
stx ji + 1
|
||||
ldx rasterIRQHigh, y
|
||||
stx ji + 2
|
||||
|
||||
ji:
|
||||
jsr $0000
|
||||
|
||||
inc nextIRQ
|
||||
ldx nextIRQ
|
||||
|
||||
ldy rasterIRQNext, x
|
||||
|
||||
asl $d019
|
||||
|
||||
cpy #$ff
|
||||
beq e2
|
||||
|
||||
dey
|
||||
sty $d012
|
||||
dey
|
||||
cpy $d012
|
||||
bcc l1
|
||||
|
||||
exd:
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rti
|
||||
|
||||
exi:
|
||||
asl $d019
|
||||
jmp exd
|
||||
|
||||
e2:
|
||||
inc rirq_count
|
||||
|
||||
ldy rasterIRQNext
|
||||
dey
|
||||
sty $d012
|
||||
ldx #0
|
||||
stx nextIRQ
|
||||
beq exd
|
||||
}
|
||||
|
||||
__asm rirq_isr_noio
|
||||
{
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
kentry:
|
||||
lda $01
|
||||
pha
|
||||
|
||||
lda #$35
|
||||
sta $01
|
||||
|
||||
ldx nextIRQ
|
||||
bmi exi
|
||||
l1:
|
||||
lda rasterIRQNext, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
ldx rasterIRQLow, y
|
||||
stx ji + 1
|
||||
ldx rasterIRQHigh, y
|
||||
stx ji + 2
|
||||
|
||||
ji:
|
||||
jsr $0000
|
||||
|
||||
inc nextIRQ
|
||||
ldx nextIRQ
|
||||
|
||||
ldy rasterIRQNext, x
|
||||
|
||||
asl $d019
|
||||
|
||||
cpy #$ff
|
||||
beq e2
|
||||
|
||||
dey
|
||||
sty $d012
|
||||
dey
|
||||
cpy $d012
|
||||
bcc l1
|
||||
|
||||
exd:
|
||||
pla
|
||||
sta $01
|
||||
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
rti
|
||||
|
||||
exi:
|
||||
asl $d019
|
||||
jmp exd
|
||||
|
||||
e2:
|
||||
inc rirq_count
|
||||
|
||||
ldy rasterIRQNext
|
||||
dey
|
||||
sty $d012
|
||||
ldx #0
|
||||
stx nextIRQ
|
||||
beq exd
|
||||
}
|
||||
|
||||
__asm rirq_isr_kernal_io
|
||||
{
|
||||
lda $d019
|
||||
bpl ex2
|
||||
|
||||
ldx nextIRQ
|
||||
bmi exi
|
||||
l1:
|
||||
lda rasterIRQNext, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
ldx rasterIRQLow, y
|
||||
stx ji + 1
|
||||
ldx rasterIRQHigh, y
|
||||
stx ji + 2
|
||||
|
||||
ji:
|
||||
jsr $0000
|
||||
jx:
|
||||
|
||||
inc nextIRQ
|
||||
ldx nextIRQ
|
||||
|
||||
ldy rasterIRQNext, x
|
||||
|
||||
asl $d019
|
||||
|
||||
cpy #$ff
|
||||
beq e2
|
||||
|
||||
dey
|
||||
dey
|
||||
sty $d012
|
||||
dey
|
||||
cpy $d012
|
||||
bcc l1
|
||||
|
||||
exd:
|
||||
jmp $ea81
|
||||
|
||||
exi:
|
||||
asl $d019
|
||||
jmp $ea81
|
||||
|
||||
e2:
|
||||
inc rirq_count
|
||||
|
||||
ldy rasterIRQNext
|
||||
dey
|
||||
dey
|
||||
sty $d012
|
||||
ldx #0
|
||||
stx nextIRQ
|
||||
jmp $ea81
|
||||
|
||||
ex2:
|
||||
LDA $DC0D
|
||||
cli
|
||||
jmp $ea31
|
||||
}
|
||||
|
||||
__asm rirq_isr_kernal_noio
|
||||
{
|
||||
lda $01
|
||||
pha
|
||||
lda #$36
|
||||
sta $01
|
||||
|
||||
lda $d019
|
||||
bpl ex2
|
||||
|
||||
ldx nextIRQ
|
||||
bmi exi
|
||||
l1:
|
||||
lda rasterIRQNext, x
|
||||
ldy rasterIRQIndex + 1, x
|
||||
ldx rasterIRQLow, y
|
||||
stx ji + 1
|
||||
ldx rasterIRQHigh, y
|
||||
stx ji + 2
|
||||
|
||||
ji:
|
||||
jsr $0000
|
||||
jx:
|
||||
|
||||
inc nextIRQ
|
||||
ldx nextIRQ
|
||||
|
||||
ldy rasterIRQNext, x
|
||||
|
||||
asl $d019
|
||||
|
||||
cpy #$ff
|
||||
beq e2
|
||||
|
||||
dey
|
||||
dey
|
||||
sty $d012
|
||||
dey
|
||||
cpy $d012
|
||||
bcc l1
|
||||
exd:
|
||||
pla
|
||||
sta $01
|
||||
|
||||
jmp $ea81
|
||||
|
||||
exi:
|
||||
asl $d019
|
||||
jmp exd
|
||||
|
||||
e2:
|
||||
inc rirq_count
|
||||
|
||||
ldy rasterIRQNext
|
||||
dey
|
||||
dey
|
||||
sty $d012
|
||||
ldx #0
|
||||
stx nextIRQ
|
||||
beq exd
|
||||
|
||||
ex2:
|
||||
LDA $DC0D
|
||||
cli
|
||||
pla
|
||||
sta $01
|
||||
|
||||
jmp $ea31
|
||||
}
|
||||
|
||||
// 0 lda #data0
|
||||
// 2 ldy #data1
|
||||
// 4 cpx $d012
|
||||
// 7 bcc -5
|
||||
// 9 sta addr0
|
||||
// 12 sty addr1
|
||||
// 15 lda #data2
|
||||
// 17 sta addr2
|
||||
// 20 lda #data3
|
||||
// 22 sta addr3
|
||||
// ...
|
||||
// rts
|
||||
|
||||
void rirq_build(RIRQCode * ic, byte size)
|
||||
{
|
||||
__assume(size < 26);
|
||||
|
||||
ic->size = size;
|
||||
|
||||
asm_im(ic->code + 0, ASM_LDY, 0);
|
||||
asm_im(ic->code + 2, ASM_LDX, 0);
|
||||
asm_ab(ic->code + 4, ASM_CMP, 0xd012);
|
||||
asm_rl(ic->code + 7, ASM_BCS, -5);
|
||||
asm_ab(ic->code + 9, ASM_STY, 0x0000);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
asm_np(ic->code + 0, ASM_RTS);
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
asm_np(ic->code + 12, ASM_RTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
asm_ab(ic->code + 12, ASM_STX, 0x0000);
|
||||
|
||||
byte p = 15;
|
||||
for(byte i=2; i<size; i++)
|
||||
{
|
||||
p += asm_im(ic->code + p, ASM_LDA, 0x00);
|
||||
p += asm_ab(ic->code + p, ASM_STA, 0x0000);
|
||||
}
|
||||
asm_np(ic->code + p, ASM_RTS);
|
||||
}
|
||||
}
|
||||
|
||||
RIRQCode * rirq_alloc(byte size)
|
||||
{
|
||||
RIRQCode * ic = (RIRQCode *)malloc(1 + RIRQ_SIZE + 5 * size);
|
||||
rirq_build(ic, size);
|
||||
return ic;
|
||||
}
|
||||
|
||||
#pragma native(rirq_build)
|
||||
|
||||
void rirq_set(byte n, byte row, RIRQCode * write)
|
||||
{
|
||||
rasterIRQLow[n] = (unsigned)&write->code & 0xff;
|
||||
rasterIRQHigh[n] = (unsigned)&write->code >> 8;
|
||||
|
||||
rasterIRQRows[n] = row;
|
||||
}
|
||||
|
||||
static const byte irqai[26] = {
|
||||
RIRQ_ADDR_0, RIRQ_ADDR_1, RIRQ_ADDR_2, RIRQ_ADDR_3, RIRQ_ADDR_4, RIRQ_ADDR_5, RIRQ_ADDR_6, RIRQ_ADDR_7,
|
||||
RIRQ_ADDR_8, RIRQ_ADDR_9, RIRQ_ADDR_10, RIRQ_ADDR_11, RIRQ_ADDR_12, RIRQ_ADDR_13, RIRQ_ADDR_14, RIRQ_ADDR_15,
|
||||
RIRQ_ADDR_16, RIRQ_ADDR_17, RIRQ_ADDR_18, RIRQ_ADDR_19, RIRQ_ADDR_20, RIRQ_ADDR_21, RIRQ_ADDR_22, RIRQ_ADDR_23,
|
||||
RIRQ_ADDR_24, RIRQ_ADDR_25
|
||||
};
|
||||
|
||||
static const byte irqdi[26] = {
|
||||
RIRQ_DATA_0, RIRQ_DATA_1, RIRQ_DATA_2, RIRQ_DATA_3, RIRQ_DATA_4, RIRQ_DATA_5, RIRQ_DATA_6, RIRQ_DATA_7,
|
||||
RIRQ_DATA_8, RIRQ_DATA_9, RIRQ_DATA_10, RIRQ_DATA_11, RIRQ_DATA_12, RIRQ_DATA_13, RIRQ_DATA_14, RIRQ_DATA_15,
|
||||
RIRQ_DATA_16, RIRQ_DATA_17, RIRQ_DATA_18, RIRQ_DATA_19, RIRQ_DATA_20, RIRQ_DATA_21, RIRQ_DATA_22, RIRQ_DATA_23,
|
||||
RIRQ_DATA_24, RIRQ_DATA_25
|
||||
};
|
||||
|
||||
void rirq_addr(RIRQCode * ic, byte n, void * addr)
|
||||
{
|
||||
byte p = irqai[n];
|
||||
((byte *)ic->code)[p + 0] = (unsigned)addr & 0xff;
|
||||
((byte *)ic->code)[p + 1] = (unsigned)addr >> 8;
|
||||
}
|
||||
|
||||
void rirq_addrhi(RIRQCode * ic, byte n, byte hi)
|
||||
{
|
||||
byte p = irqai[n];
|
||||
((byte *)ic->code)[p + 1] = hi;
|
||||
}
|
||||
|
||||
void rirq_data(RIRQCode * ic, byte n, byte data)
|
||||
{
|
||||
byte p = irqdi[n];
|
||||
// ic->code[p] = data;
|
||||
(volatile char *)(ic->code)[p] = data;
|
||||
}
|
||||
|
||||
void rirq_write(RIRQCode * ic, byte n, void * addr, byte data)
|
||||
{
|
||||
byte p = irqai[n];
|
||||
((byte *)ic->code)[p + 0] = (unsigned)addr & 0xff;
|
||||
((byte *)ic->code)[p + 1] = (unsigned)addr >> 8;
|
||||
p = irqdi[n];
|
||||
((byte *)ic->code)[p] = data;
|
||||
}
|
||||
|
||||
void rirq_call(RIRQCode * ic, byte n, void * addr)
|
||||
{
|
||||
byte p = irqai[n];
|
||||
((byte *)ic->code)[p - 1] = 0x20;
|
||||
((byte *)ic->code)[p + 0] = (unsigned)addr & 0xff;
|
||||
((byte *)ic->code)[p + 1] = (unsigned)addr >> 8;
|
||||
}
|
||||
|
||||
void rirq_delay(RIRQCode * ic, byte cycles)
|
||||
{
|
||||
ic->code[ 1] = cycles;
|
||||
ic->code[ 9] = 0x88; // dey
|
||||
ic->code[10] = 0xd0; // bne
|
||||
ic->code[11] = 0xfd; // -3
|
||||
}
|
||||
|
||||
|
||||
void rirq_move(byte n, byte row)
|
||||
{
|
||||
rasterIRQRows[n] = row;
|
||||
}
|
||||
|
||||
void rirq_clear(byte n)
|
||||
{
|
||||
rasterIRQRows[n] = 255;
|
||||
}
|
||||
|
||||
void rirq_init_tables(void)
|
||||
{
|
||||
for(byte i=0; i<NUM_IRQS; i++)
|
||||
{
|
||||
rasterIRQRows[i] = 255;
|
||||
rasterIRQIndex[i + 1] = i;
|
||||
}
|
||||
rasterIRQIndex[0] = NUM_IRQS;
|
||||
rasterIRQRows[NUM_IRQS] = 0;
|
||||
rasterIRQNext[NUM_IRQS] = 255;
|
||||
}
|
||||
|
||||
void rirq_init_kernal(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
*(void **)0x0314 = rirq_isr_kernal_io;
|
||||
|
||||
vic.intr_enable = 1;
|
||||
vic.ctrl1 &= 0x7f;
|
||||
vic.raster = 255;
|
||||
|
||||
}
|
||||
|
||||
void rirq_init_kernal_noio(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
*(void **)0x0314 = rirq_isr_kernal_noio;
|
||||
|
||||
vic.intr_enable = 1;
|
||||
vic.ctrl1 &= 0x7f;
|
||||
vic.raster = 255;
|
||||
|
||||
}
|
||||
|
||||
void rirq_init_crt(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
*(void **)0x0314 = rirq_isr_io.kentry;
|
||||
*(void **)0xfffe = rirq_isr_io;
|
||||
|
||||
vic.intr_enable = 1;
|
||||
vic.ctrl1 &= 0x7f;
|
||||
vic.raster = 255;
|
||||
|
||||
}
|
||||
|
||||
void rirq_init_crt_noio(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
*(void **)0x0314 = rirq_isr_noio.kentry;
|
||||
*(void **)0xfffe = rirq_isr_noio;
|
||||
|
||||
vic.intr_enable = 1;
|
||||
vic.ctrl1 &= 0x7f;
|
||||
vic.raster = 255;
|
||||
|
||||
}
|
||||
|
||||
void rirq_init_io(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
*(void **)0xfffe = rirq_isr_ram_io;
|
||||
|
||||
vic.intr_enable = 1;
|
||||
vic.ctrl1 &= 0x7f;
|
||||
vic.raster = 255;
|
||||
|
||||
}
|
||||
|
||||
void rirq_init_memmap(void)
|
||||
{
|
||||
rirq_init_tables();
|
||||
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
*(void **)0xfffe = rirq_isr_noio;
|
||||
|
||||
vic.intr_enable = 1;
|
||||
vic.ctrl1 &= 0x7f;
|
||||
vic.raster = 255;
|
||||
|
||||
}
|
||||
|
||||
void rirq_init(bool kernalIRQ)
|
||||
{
|
||||
if (kernalIRQ)
|
||||
rirq_init_kernal();
|
||||
else
|
||||
rirq_init_io();
|
||||
}
|
||||
|
||||
void rirq_wait(void)
|
||||
{
|
||||
char i0 = rirq_pcount;
|
||||
char i1;
|
||||
do {
|
||||
i1 = rirq_count;
|
||||
} while (i0 == i1);
|
||||
rirq_pcount = i1;
|
||||
}
|
||||
|
||||
void rirq_wait_done(void)
|
||||
{
|
||||
do {
|
||||
|
||||
} while (nextIRQ != 0);
|
||||
}
|
||||
|
||||
void rirq_sort(bool inirq)
|
||||
{
|
||||
// disable raster interrupts while sorting
|
||||
nextIRQ = 0xff;
|
||||
#if 1
|
||||
byte maxr = rasterIRQRows[rasterIRQIndex[1]];
|
||||
for(byte i = 2; i<NUM_IRQS + 1; i++)
|
||||
{
|
||||
byte ri = rasterIRQIndex[i];
|
||||
byte rr = rasterIRQRows[ri];
|
||||
if (rr < maxr)
|
||||
{
|
||||
rasterIRQIndex[i] = rasterIRQIndex[i - 1];
|
||||
byte j = i, rj;
|
||||
while (rr < rasterIRQRows[(rj = rasterIRQIndex[j - 2])])
|
||||
{
|
||||
rasterIRQIndex[j - 1] = rj;
|
||||
j--;
|
||||
}
|
||||
rasterIRQIndex[j - 1] = ri;
|
||||
}
|
||||
else
|
||||
maxr = rr;
|
||||
}
|
||||
#else
|
||||
for(byte i = 1; i<NUM_IRQS; i++)
|
||||
{
|
||||
byte ri = rasterIRQIndex[i];
|
||||
byte rr = rasterIRQRows[ri];
|
||||
byte j = i, rj;
|
||||
while (j > 0 && rr < rasterIRQRows[(rj = rasterIRQIndex[j - 1])])
|
||||
{
|
||||
rasterIRQIndex[j] = rj;
|
||||
j--;
|
||||
}
|
||||
rasterIRQIndex[j] = ri;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NUM_IRQS & 3
|
||||
for(sbyte i=NUM_IRQS-1; i>=0; i--)
|
||||
rasterIRQNext[i] = rasterIRQRows[rasterIRQIndex[i + 1]];
|
||||
#else
|
||||
for(sbyte i=NUM_IRQS/4-1; i>=0; i--)
|
||||
{
|
||||
#pragma unroll(full)
|
||||
for(int j=0; j<4; j++)
|
||||
rasterIRQNext[i + j * NUM_IRQS / 4] = rasterIRQRows[rasterIRQIndex[i + j * NUM_IRQS / 4 + 1]];
|
||||
}
|
||||
#endif
|
||||
|
||||
rirq_pcount = rirq_count;
|
||||
if (inirq)
|
||||
nextIRQ = NUM_IRQS - 1;
|
||||
else
|
||||
{
|
||||
byte yp = rasterIRQNext[0];
|
||||
if (yp != 0xff)
|
||||
{
|
||||
vic.raster = yp - 1;
|
||||
nextIRQ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rirq_start(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
lda $d011
|
||||
and #$7f
|
||||
sta $d011
|
||||
|
||||
lda #100
|
||||
sta $d012
|
||||
|
||||
asl $d019
|
||||
cli
|
||||
}
|
||||
}
|
||||
|
||||
void rirq_stop(void)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(rirq_sort)
|
||||
#pragma native(rirq_wait)
|
||||
#pragma native(rirq_start)
|
||||
#pragma native(rirq_stop)
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
#ifndef C64_RASTERIRQ_H
|
||||
#define C64_RASTERIRQ_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifndef NUM_IRQS
|
||||
#define NUM_IRQS 16
|
||||
#endif
|
||||
|
||||
extern volatile byte rirq_count;
|
||||
|
||||
enum RIRQCodeIndex
|
||||
{
|
||||
RIRQ_DATA_0 = 1,
|
||||
RIRQ_DATA_1 = 3,
|
||||
|
||||
RIRQ_ADDR_0 = 10,
|
||||
RIRQ_ADDR_1 = 13,
|
||||
|
||||
RIRQ_DATA_2 = 16,
|
||||
RIRQ_ADDR_2 = 18,
|
||||
|
||||
RIRQ_DATA_3 = 21,
|
||||
RIRQ_ADDR_3 = 23,
|
||||
|
||||
RIRQ_DATA_4 = 26,
|
||||
RIRQ_ADDR_4 = 28,
|
||||
|
||||
RIRQ_SIZE = 31,
|
||||
|
||||
RIRQ_DATA_5 = 31,
|
||||
RIRQ_ADDR_5 = 33,
|
||||
|
||||
RIRQ_DATA_6 = 36,
|
||||
RIRQ_ADDR_6 = 38,
|
||||
|
||||
RIRQ_DATA_7 = 41,
|
||||
RIRQ_ADDR_7 = 43,
|
||||
|
||||
RIRQ_DATA_8 = 46,
|
||||
RIRQ_ADDR_8 = 48,
|
||||
|
||||
RIRQ_DATA_9 = 51,
|
||||
RIRQ_ADDR_9 = 53,
|
||||
|
||||
RIRQ_DATA_10 = 56,
|
||||
RIRQ_ADDR_10 = 58,
|
||||
|
||||
RIRQ_SIZE_10 = 61,
|
||||
|
||||
RIRQ_DATA_11 = 61,
|
||||
RIRQ_ADDR_11 = 63,
|
||||
|
||||
RIRQ_DATA_12 = 66,
|
||||
RIRQ_ADDR_12 = 68,
|
||||
|
||||
RIRQ_DATA_13 = 71,
|
||||
RIRQ_ADDR_13 = 73,
|
||||
|
||||
RIRQ_DATA_14 = 76,
|
||||
RIRQ_ADDR_14 = 78,
|
||||
|
||||
RIRQ_DATA_15 = 81,
|
||||
RIRQ_ADDR_15 = 83,
|
||||
|
||||
RIRQ_DATA_16 = 86,
|
||||
RIRQ_ADDR_16 = 88,
|
||||
|
||||
RIRQ_DATA_17 = 91,
|
||||
RIRQ_ADDR_17 = 93,
|
||||
|
||||
RIRQ_DATA_18 = 96,
|
||||
RIRQ_ADDR_18 = 98,
|
||||
|
||||
RIRQ_DATA_19 = 101,
|
||||
RIRQ_ADDR_19 = 103,
|
||||
|
||||
RIRQ_SIZE_20 = 106,
|
||||
|
||||
RIRQ_DATA_20 = 106,
|
||||
RIRQ_ADDR_20 = 108,
|
||||
|
||||
RIRQ_DATA_21 = 111,
|
||||
RIRQ_ADDR_21 = 113,
|
||||
|
||||
RIRQ_DATA_22 = 116,
|
||||
RIRQ_ADDR_22 = 118,
|
||||
|
||||
RIRQ_DATA_23 = 121,
|
||||
RIRQ_ADDR_23 = 123,
|
||||
|
||||
RIRQ_DATA_24 = 126,
|
||||
RIRQ_ADDR_24 = 128,
|
||||
|
||||
RIRQ_DATA_25 = 131,
|
||||
RIRQ_ADDR_25 = 133
|
||||
};
|
||||
|
||||
// One raster interrupt operation, handles up to five writes
|
||||
// to arbitrary memory location, or one wait and four writes.
|
||||
typedef struct RIRQCode
|
||||
{
|
||||
byte size;
|
||||
byte code[RIRQ_SIZE];
|
||||
} RIRQCode;
|
||||
|
||||
typedef struct RIRQCode10
|
||||
{
|
||||
RIRQCode c;
|
||||
byte code[RIRQ_SIZE_10 - RIRQ_SIZE];
|
||||
} RIRQCode10;
|
||||
|
||||
typedef struct RIRQCode20
|
||||
{
|
||||
RIRQCode c;
|
||||
byte code[RIRQ_SIZE_20 - RIRQ_SIZE];
|
||||
} RIRQCode20;
|
||||
|
||||
// Build one raster IRQ operation of the given size (wait + #ops) for up to 5 instructions
|
||||
void rirq_build(RIRQCode * ic, byte size);
|
||||
|
||||
// Allocate one raster IRQ operation of the given size (wait + #ops)
|
||||
RIRQCode * rirq_alloc(byte size);
|
||||
|
||||
// Add a write command to a raster IRQ
|
||||
inline void rirq_write(RIRQCode * ic, byte n, void * addr, byte data);
|
||||
|
||||
// Add a call command to a raster IRQ
|
||||
inline void rirq_call(RIRQCode * ic, byte n, void * addr);
|
||||
|
||||
// Change the address of a raster IRQ write command
|
||||
inline void rirq_addr(RIRQCode * ic, byte n, void * addr);
|
||||
|
||||
// Change the high byte of the address of a raster IRQ write command
|
||||
inline void rirq_addrhi(RIRQCode * ic, byte n, byte hi);
|
||||
|
||||
// Change the data of a raster IRQ write command
|
||||
inline void rirq_data(RIRQCode * ic, byte n, byte data);
|
||||
|
||||
// Add a delay of 5 * cycles to a raster IRQ
|
||||
inline void rirq_delay(RIRQCode * ic, byte cycles);
|
||||
|
||||
// Place a raster IRQ into one of the 16 slots, the interrupt will fire
|
||||
// one line below the given row
|
||||
inline void rirq_set(byte n, byte row, RIRQCode * write);
|
||||
|
||||
// Remove a raster IRQ from one of the 16 slots
|
||||
inline void rirq_clear(byte n);
|
||||
|
||||
// Change the vertical position of the raster IRQ of one of the slots
|
||||
inline void rirq_move(byte n, byte row);
|
||||
|
||||
|
||||
// Initialize the raster IRQ system with either the kernal IRQ vector
|
||||
// or the hardware IRQ vector if the kernal ROM is turned off (which is
|
||||
// the less resource hungry option)
|
||||
inline void rirq_init(bool kernalIRQ);
|
||||
|
||||
// Raster IRQ through kernal, with IO range always enabled
|
||||
// calls kernal continuation
|
||||
void rirq_init_kernal(void);
|
||||
|
||||
// Raster IRQ through kernal, with IO range not always enabled
|
||||
// calls kernal continuation
|
||||
void rirq_init_kernal_noio(void);
|
||||
|
||||
// Raster IRQ through RAM and ROM vector, with ROM disabled or not and IO range always enabled
|
||||
// does not call kernal continuation
|
||||
void rirq_init_crt(void);
|
||||
|
||||
// Raster IRQ through RAM and ROM vector, with ROM disabled or not and IO range not always enabled
|
||||
// does not call kernal continuation
|
||||
void rirq_init_crt_noio(void);
|
||||
|
||||
// Raster IRQ through RAM vector, with ROM disabled and IO range always enabled
|
||||
// does not call kernal continuation
|
||||
void rirq_init_io(void);
|
||||
|
||||
// Raster IRQ through RAM vector, with ROM disabled and IO range not always enabled
|
||||
// does not call kernal continuation
|
||||
void rirq_init_memmap(void);
|
||||
|
||||
// Start raster IRQ
|
||||
void rirq_start(void);
|
||||
|
||||
// Stop raster IRQ
|
||||
void rirq_stop(void);
|
||||
|
||||
// Sort the raster IRQ, must be performed at the end of the frame after changing
|
||||
// the vertical position of one of the interrupt operations.
|
||||
// Set the inirq flag to true when calling this from an interrupt
|
||||
void rirq_sort(bool inirq = false);
|
||||
|
||||
// Wait for the last raster IRQ op to have completed. Must be called before a
|
||||
// sort if the raster IRQ system is active
|
||||
void rirq_wait_done(void);
|
||||
|
||||
void rirq_wait(void);
|
||||
|
||||
#pragma compile("rasterirq.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,97 @@
|
||||
#include "reu.h"
|
||||
|
||||
int reu_count_pages(void)
|
||||
{
|
||||
volatile char c, d;
|
||||
|
||||
c = 0;
|
||||
reu_store(0, &c, 1);
|
||||
reu_load(0, &d, 1);
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
c = 0x47;
|
||||
reu_store(0, &c, 1);
|
||||
reu_load(0, &d, 1);
|
||||
|
||||
if (d == 0x47)
|
||||
{
|
||||
for(int i=1; i<256; i++)
|
||||
{
|
||||
long l = (long)i << 16;
|
||||
c = 0x47;
|
||||
reu_store(l, &c, 1);
|
||||
c = 0x00;
|
||||
reu_store(0, &c, 1);
|
||||
|
||||
reu_load(l, &d, 1);
|
||||
if (d != 0x47)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 256;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void reu_store(unsigned long raddr, const volatile char * sp, unsigned length)
|
||||
{
|
||||
reu.laddr = (word)sp;
|
||||
reu.raddr = raddr;
|
||||
reu.rbank = raddr >> 16;
|
||||
reu.length = length;
|
||||
reu.ctrl = REU_CTRL_INCL | REU_CTRL_INCR;
|
||||
reu.cmd = REU_CMD_EXEC | REU_CMD_FF00 | REU_CMD_STORE;
|
||||
|
||||
}
|
||||
|
||||
inline void reu_load(unsigned long raddr, volatile char * dp, unsigned length)
|
||||
{
|
||||
reu.laddr = (word)dp;
|
||||
reu.raddr = raddr;
|
||||
reu.rbank = raddr >> 16;
|
||||
reu.length = length;
|
||||
reu.ctrl = REU_CTRL_INCL | REU_CTRL_INCR;
|
||||
reu.cmd = REU_CMD_EXEC | REU_CMD_FF00 | REU_CMD_LOAD;
|
||||
}
|
||||
|
||||
inline void reu_fill(unsigned long raddr, char c, unsigned length)
|
||||
{
|
||||
reu.laddr = (word)&c;
|
||||
reu.raddr = raddr;
|
||||
reu.rbank = raddr >> 16;
|
||||
reu.length = length;
|
||||
reu.ctrl = REU_CTRL_FIXL | REU_CTRL_INCR;
|
||||
reu.cmd = REU_CMD_EXEC | REU_CMD_FF00 | REU_CMD_STORE;
|
||||
}
|
||||
|
||||
inline void reu_load2d(unsigned long raddr, volatile char * dp, char height, unsigned width, unsigned stride)
|
||||
{
|
||||
reu.ctrl = REU_CTRL_INCL | REU_CTRL_INCR;
|
||||
reu.laddr = (word)dp;
|
||||
for(char i=0; i<height; i++)
|
||||
{
|
||||
reu.length = width;
|
||||
reu.raddr = raddr;
|
||||
reu.rbank = raddr >> 16;
|
||||
reu.cmd = REU_CMD_EXEC | REU_CMD_FF00 | REU_CMD_LOAD;
|
||||
raddr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
inline void reu_load2dpage(unsigned long raddr, volatile char * dp, char height, unsigned width, unsigned stride)
|
||||
{
|
||||
reu.ctrl = REU_CTRL_INCL | REU_CTRL_INCR;
|
||||
reu.laddr = (word)dp;
|
||||
reu.rbank = raddr >> 16;
|
||||
for(char i=0; i<height; i++)
|
||||
{
|
||||
reu.length = width;
|
||||
reu.raddr = raddr;
|
||||
reu.cmd = REU_CMD_EXEC | REU_CMD_FF00 | REU_CMD_LOAD;
|
||||
raddr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef C64_REU_H
|
||||
#define C64_REU_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define REU_STAT_IRQ 0x80
|
||||
#define REU_STAT_EOB 0x40
|
||||
#define REU_STAT_FAULT 0x20
|
||||
#define REU_STAT_SIZE 0x10
|
||||
#define REU_STAT_VERSION 0x0f
|
||||
|
||||
#define REU_CTRL_FIXL 0x80
|
||||
#define REU_CTRL_FIXR 0x40
|
||||
#define REU_CTRL_INCL 0x00
|
||||
#define REU_CTRL_INCR 0x00
|
||||
|
||||
#define REU_IRQ_ENABLE 0x80
|
||||
#define REU_IRQ_EOB 0x40
|
||||
#define REU_IRQ_FAULT 0x20
|
||||
|
||||
#define REU_CMD_EXEC 0x80
|
||||
#define REU_CMD_AUTO 0x20
|
||||
#define REU_CMD_FF00 0x10
|
||||
#define REU_CMD_STORE 0x00
|
||||
#define REU_CMD_LOAD 0x01
|
||||
#define REU_CMD_SWAP 0x02
|
||||
#define REU_CMD_VERIFY 0x03
|
||||
|
||||
struct REU
|
||||
{
|
||||
volatile byte status;
|
||||
volatile __memmap byte cmd;
|
||||
|
||||
volatile word laddr;
|
||||
volatile word raddr;
|
||||
volatile byte rbank;
|
||||
|
||||
volatile word length;
|
||||
|
||||
volatile byte irqmask;
|
||||
volatile byte ctrl;
|
||||
};
|
||||
|
||||
|
||||
#define reu (*((struct REU *)0xdf00))
|
||||
|
||||
// Count the number of 64k pages in the REU, the test is destructive
|
||||
int reu_count_pages(void);
|
||||
|
||||
// Copy an array of data from C64 memory to the REU memory
|
||||
inline void reu_store(unsigned long raddr, const volatile char * sp, unsigned length);
|
||||
|
||||
// Copy an array of data from REU memory to the C64 memory
|
||||
inline void reu_load(unsigned long raddr, volatile char * dp, unsigned length);
|
||||
|
||||
// Fill an array of data in the REU with a single value
|
||||
inline void reu_fill(unsigned long raddr, char c, unsigned length);
|
||||
|
||||
// Copy a 2D array from REU memory to the C64 memory. The stride parameter
|
||||
// is the distance of two rows in REU memory
|
||||
inline void reu_load2d(unsigned long raddr, volatile char * dp, char height, unsigned width, unsigned stride);
|
||||
|
||||
|
||||
inline void reu_load2dpage(unsigned long raddr, volatile char * dp, char height, unsigned width, unsigned stride);
|
||||
|
||||
#pragma compile("reu.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "sid.h"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifndef C64_SID_H
|
||||
#define C64_SID_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define SID_ATK_2 0x00
|
||||
#define SID_ATK_8 0x10
|
||||
#define SID_ATK_16 0x20
|
||||
#define SID_ATK_24 0x30
|
||||
#define SID_ATK_38 0x40
|
||||
#define SID_ATK_56 0x50
|
||||
#define SID_ATK_68 0x60
|
||||
#define SID_ATK_80 0x70
|
||||
#define SID_ATK_100 0x80
|
||||
#define SID_ATK_250 0x90
|
||||
#define SID_ATK_500 0xa0
|
||||
#define SID_ATK_800 0xb0
|
||||
#define SID_ATK_1000 0xc0
|
||||
#define SID_ATK_3000 0xd0
|
||||
#define SID_ATK_5000 0xe0
|
||||
#define SID_ATK_8000 0xf0
|
||||
|
||||
#define SID_DKY_6 0x00
|
||||
#define SID_DKY_24 0x01
|
||||
#define SID_DKY_48 0x02
|
||||
#define SID_DKY_72 0x03
|
||||
#define SID_DKY_114 0x04
|
||||
#define SID_DKY_168 0x05
|
||||
#define SID_DKY_204 0x06
|
||||
#define SID_DKY_240 0x07
|
||||
#define SID_DKY_300 0x08
|
||||
#define SID_DKY_750 0x09
|
||||
#define SID_DKY_1500 0x0a
|
||||
#define SID_DKY_2400 0x0b
|
||||
#define SID_DKY_3000 0x0c
|
||||
#define SID_DKY_9000 0x0d
|
||||
#define SID_DKY_15000 0x0e
|
||||
#define SID_DKY_24000 0x0f
|
||||
|
||||
#define SID_CTRL_GATE 0x01
|
||||
#define SID_CTRL_SYNC 0x02
|
||||
#define SID_CTRL_RING 0x04
|
||||
#define SID_CTRL_TEST 0x08
|
||||
#define SID_CTRL_TRI 0x10
|
||||
#define SID_CTRL_SAW 0x20
|
||||
#define SID_CTRL_RECT 0x40
|
||||
#define SID_CTRL_NOISE 0x80
|
||||
|
||||
#define SID_FILTER_1 0x01
|
||||
#define SID_FILTER_2 0x02
|
||||
#define SID_FILTER_3 0x04
|
||||
#define SID_FILTER_X 0x08
|
||||
|
||||
#define SID_FMODE_LP 0x10
|
||||
#define SID_FMODE_BP 0x20
|
||||
#define SID_FMODE_HP 0x40
|
||||
#define SID_FMODE_3_OFF 0x80
|
||||
|
||||
#define SID_CLOCK_PAL 985248
|
||||
#define SID_CLOCK_NTSC 1022727
|
||||
|
||||
#define SID_CLKSCALE_PAL 1115974UL
|
||||
#define SID_CLKSCALE_NTSC 1075078UL
|
||||
|
||||
#define SID_FREQ_PAL(f) ((unsigned)(((unsigned long)(f) * SID_CLKSCALE_PAL) >> 16))
|
||||
#define SID_FREQ_NTSC(f) ((unsigned)(((unsigned long)(f) * SID_CLKSCALE_NTSC) >> 16))
|
||||
|
||||
struct SID
|
||||
{
|
||||
struct Voice
|
||||
{
|
||||
volatile unsigned freq;
|
||||
volatile unsigned pwm;
|
||||
volatile byte ctrl;
|
||||
volatile byte attdec;
|
||||
volatile byte susrel;
|
||||
} voices[3];
|
||||
|
||||
volatile unsigned ffreq;
|
||||
volatile byte resfilt;
|
||||
volatile byte fmodevol;
|
||||
|
||||
volatile byte potx;
|
||||
volatile byte poty;
|
||||
volatile byte random;
|
||||
volatile byte env3;
|
||||
};
|
||||
|
||||
#define NOTE_C(o) (16744U >> (10 - (o)))
|
||||
#define NOTE_CS(o) (17740U >> (10 - (o)))
|
||||
#define NOTE_D(o) (18794U >> (10 - (o)))
|
||||
#define NOTE_DS(o) (19912U >> (10 - (o)))
|
||||
#define NOTE_E(o) (21096U >> (10 - (o)))
|
||||
#define NOTE_F(o) (22351U >> (10 - (o)))
|
||||
#define NOTE_FS(o) (23680U >> (10 - (o)))
|
||||
#define NOTE_G(o) (25087U >> (10 - (o)))
|
||||
#define NOTE_GS(o) (26580U >> (10 - (o)))
|
||||
#define NOTE_A(o) (28160U >> (10 - (o)))
|
||||
#define NOTE_AS(o) (29834U >> (10 - (o)))
|
||||
#define NOTE_B(o) (31068U >> (10 - (o)))
|
||||
|
||||
// reference to the SID chip
|
||||
#define sid (*((struct SID *)0xd400))
|
||||
|
||||
#pragma compile("sid.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,346 @@
|
||||
#include "sprites.h"
|
||||
#include "rasterirq.h"
|
||||
|
||||
static volatile char * vspriteScreen;
|
||||
|
||||
#ifdef VSPRITE_BSS
|
||||
#pragma bss(VSPRITE_BSS)
|
||||
#endif
|
||||
|
||||
void spr_init(char * screen)
|
||||
{
|
||||
vspriteScreen = screen + 0x3f8;
|
||||
}
|
||||
|
||||
|
||||
void spr_set(char sp, bool show, int xpos, int ypos, char image, char color, bool multi, bool xexpand, bool yexpand)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
char m = 1 << sp;
|
||||
|
||||
if (show)
|
||||
vic.spr_enable |= m;
|
||||
else
|
||||
vic.spr_enable &= ~m;
|
||||
|
||||
if (multi)
|
||||
vic.spr_multi |= m;
|
||||
else
|
||||
vic.spr_multi &= ~m;
|
||||
|
||||
if (xexpand)
|
||||
vic.spr_expand_x |= m;
|
||||
else
|
||||
vic.spr_expand_x &= ~m;
|
||||
|
||||
if (yexpand)
|
||||
vic.spr_expand_y |= m;
|
||||
else
|
||||
vic.spr_expand_y &= ~m;
|
||||
|
||||
vic.spr_pos[sp].y = ypos;
|
||||
vic.spr_pos[sp].x = xpos & 0xff;
|
||||
if (xpos & 0x100)
|
||||
vic.spr_msbx |= m;
|
||||
else
|
||||
vic.spr_msbx &= ~m;
|
||||
|
||||
vspriteScreen[sp] = image;
|
||||
vic.spr_color[sp] = color;
|
||||
}
|
||||
|
||||
void spr_show(char sp, bool show)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
if (show)
|
||||
vic.spr_enable |= 1 << sp;
|
||||
else
|
||||
vic.spr_enable &= ~(1 << sp);
|
||||
}
|
||||
|
||||
void spr_move(char sp, int xpos, int ypos)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
vic.spr_pos[sp].y = ypos;
|
||||
vic.spr_pos[sp].x = xpos & 0xff;
|
||||
if (xpos & 0x100)
|
||||
vic.spr_msbx |= 1 << sp;
|
||||
else
|
||||
vic.spr_msbx &= ~(1 << sp);
|
||||
}
|
||||
|
||||
void spr_move16(char sp, int xpos, int ypos)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
if (ypos < 0 || ypos >= 256 || xpos < 0 || xpos >= 384)
|
||||
xpos = 384;
|
||||
|
||||
vic.spr_pos[sp].y = ypos;
|
||||
vic.spr_pos[sp].x = xpos & 0xff;
|
||||
if (xpos & 0x100)
|
||||
vic.spr_msbx |= 1 << sp;
|
||||
else
|
||||
vic.spr_msbx &= ~(1 << sp);
|
||||
}
|
||||
|
||||
int spr_posx(char sp)
|
||||
{
|
||||
return vic.spr_pos[sp].x | ((vic.spr_msbx & (1 << sp)) ? 256 : 0);
|
||||
}
|
||||
|
||||
int spr_posy(char sp)
|
||||
{
|
||||
return vic.spr_pos[sp].y;
|
||||
}
|
||||
|
||||
void spr_image(char sp, char image)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
vspriteScreen[sp] = image;
|
||||
}
|
||||
|
||||
void spr_color(char sp, char color)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
vic.spr_color[sp] = color;
|
||||
}
|
||||
|
||||
void spr_expand(char sp, bool xexpand, bool yexpand)
|
||||
{
|
||||
__assume (sp < 8);
|
||||
|
||||
char m = 1 << sp;
|
||||
|
||||
if (xexpand)
|
||||
vic.spr_expand_x |= m;
|
||||
else
|
||||
vic.spr_expand_x &= ~m;
|
||||
|
||||
if (yexpand)
|
||||
vic.spr_expand_y |= m;
|
||||
else
|
||||
vic.spr_expand_y &= ~m;
|
||||
}
|
||||
|
||||
static char vspriteYLow[VSPRITES_MAX], vspriteXLow[VSPRITES_MAX], vspriteXHigh[VSPRITES_MAX];
|
||||
static char vspriteImage[VSPRITES_MAX], vspriteColor[VSPRITES_MAX];
|
||||
|
||||
static char spriteOrder[VSPRITES_MAX], spriteYPos[VSPRITES_MAX + 1];
|
||||
|
||||
static RIRQCode spirq[VSPRITES_MAX - 8], synch;
|
||||
|
||||
|
||||
void vspr_init(char * screen)
|
||||
{
|
||||
vspriteScreen = screen + 0x3f8;
|
||||
|
||||
vic.spr_expand_x = 0;
|
||||
vic.spr_expand_y = 0;
|
||||
vic.spr_enable = 0xff;
|
||||
|
||||
for(int i=0; i<VSPRITES_MAX - 8; i++)
|
||||
{
|
||||
#ifdef VSPRITE_REVERSE
|
||||
int j = (i & 7) ^ 7;
|
||||
#else
|
||||
int j = i & 7;
|
||||
#endif
|
||||
|
||||
rirq_build(spirq + i, 5);
|
||||
rirq_write(spirq + i, 0, &vic.spr_color[j], 0);
|
||||
rirq_write(spirq + i, 1, &vic.spr_pos[j].x, 0);
|
||||
rirq_write(spirq + i, 2, &vic.spr_pos[j].y, 0);
|
||||
rirq_write(spirq + i, 3, &vspriteScreen[j], 0);
|
||||
rirq_write(spirq + i, 4, &vic.spr_msbx, 0);
|
||||
rirq_set(i, 80 + 4 * i, spirq + i);
|
||||
}
|
||||
|
||||
rirq_build(&synch, 0);
|
||||
rirq_set(VSPRITES_MAX - 8, 250, &synch);
|
||||
|
||||
for(int i=0; i<VSPRITES_MAX; i++)
|
||||
{
|
||||
spriteOrder[i] = i;
|
||||
vspriteYLow[i] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void vspr_shutdown(void)
|
||||
{
|
||||
for(int i=0; i<VSPRITES_MAX - 7; i++)
|
||||
rirq_clear(i);
|
||||
}
|
||||
|
||||
void vspr_screen(char * screen)
|
||||
{
|
||||
vspriteScreen = screen + 0x3f8;
|
||||
char hi = (unsigned)vspriteScreen >> 8;
|
||||
#pragma unroll(8)
|
||||
for(int i=0; i<VSPRITES_MAX - 8; i++)
|
||||
rirq_addrhi(spirq + i, 3, hi);
|
||||
}
|
||||
|
||||
#pragma native(vspr_init)
|
||||
|
||||
void vspr_set(char sp, int xpos, int ypos, char image, char color)
|
||||
{
|
||||
char yp = (char)ypos;
|
||||
if ((ypos & 0xff00 ) || (xpos & 0xfe00))
|
||||
yp = 0xff;
|
||||
|
||||
vspriteYLow[sp] = yp;
|
||||
vspriteXLow[sp] = (char)xpos;
|
||||
vspriteXHigh[sp] = (char)(xpos >> 8);
|
||||
vspriteImage[sp] = image;
|
||||
vspriteColor[sp] = color;
|
||||
}
|
||||
|
||||
#pragma native(vspr_set)
|
||||
|
||||
void vspr_move(char sp, int xpos, int ypos)
|
||||
{
|
||||
char yp = (char)ypos;
|
||||
if ((ypos & 0xff00 ) || (xpos & 0xfe00))
|
||||
yp = 0xff;
|
||||
|
||||
vspriteYLow[sp] = yp;
|
||||
vspriteXLow[sp] = (char)xpos;
|
||||
vspriteXHigh[sp] = (char)(xpos >> 8);
|
||||
}
|
||||
|
||||
void vspr_movex(char sp, int xpos)
|
||||
{
|
||||
vspriteXLow[sp] = (char)xpos;
|
||||
vspriteXHigh[sp] = (char)(xpos >> 8);
|
||||
}
|
||||
|
||||
void vspr_movey(char sp, int ypos)
|
||||
{
|
||||
char yp = (char)ypos;
|
||||
if (ypos & 0xff00)
|
||||
yp = 0xff;
|
||||
|
||||
vspriteYLow[sp] = yp;
|
||||
}
|
||||
|
||||
void vspr_image(char sp, char image)
|
||||
{
|
||||
vspriteImage[sp] = image;
|
||||
}
|
||||
|
||||
void vspr_color(char sp, char color)
|
||||
{
|
||||
vspriteColor[sp] = color;
|
||||
}
|
||||
|
||||
void vspr_hide(char sp)
|
||||
{
|
||||
vspriteYLow[sp] = 0xff;
|
||||
}
|
||||
|
||||
void vspr_sort(void)
|
||||
{
|
||||
byte rm = vspriteYLow[spriteOrder[0]];
|
||||
spriteYPos[1] = rm;
|
||||
|
||||
for(char i = 1; i<VSPRITES_MAX; i++)
|
||||
{
|
||||
byte ri = spriteOrder[i];
|
||||
byte rr = vspriteYLow[ri];
|
||||
if (rr < rm)
|
||||
{
|
||||
byte j = i, rj = rm;
|
||||
do {
|
||||
spriteYPos[j + 1] = rj;
|
||||
spriteOrder[j] = spriteOrder[j - 1];
|
||||
rj = spriteYPos[j - 1];
|
||||
j--;
|
||||
} while (rr < rj);
|
||||
spriteOrder[j] = ri;
|
||||
spriteYPos[j + 1] = rr;
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteYPos[i + 1] = rr;
|
||||
rm = rr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(vspr_sort)
|
||||
|
||||
void vspr_update(void)
|
||||
{
|
||||
char xymask = 0;
|
||||
volatile char * vsprs = vspriteScreen;
|
||||
// char sypos[VSPRITES_MAX];
|
||||
|
||||
#pragma unroll(full)
|
||||
|
||||
for(char ui=0; ui<8; ui++)
|
||||
{
|
||||
byte ri = spriteOrder[ui];
|
||||
#ifdef VSPRITE_REVERSE
|
||||
char uj = ui ^ 7;
|
||||
#else
|
||||
char uj = ui;
|
||||
#endif
|
||||
|
||||
vic.spr_color[uj] = vspriteColor[ri];
|
||||
vsprs[uj] = vspriteImage[ri];
|
||||
#ifdef VSPRITE_REVERSE
|
||||
xymask = (xymask << 1) | (vspriteXHigh[ri] & 1);
|
||||
#else
|
||||
xymask = ((unsigned)xymask | (vspriteXHigh[ri] << 8)) >> 1;
|
||||
#endif
|
||||
vic.spr_pos[uj].x = vspriteXLow[ri];
|
||||
vic.spr_pos[uj].y = spriteYPos[ui + 1];
|
||||
|
||||
// sypos[ui] = vspriteYLow[ri];
|
||||
}
|
||||
|
||||
vic.spr_msbx = xymask;
|
||||
|
||||
#pragma unroll(full)
|
||||
bool done = false;
|
||||
|
||||
for(char ti=0; ti<VSPRITES_MAX - 8; ti++)
|
||||
{
|
||||
if (!done && spriteYPos[ti + 9] < 250)
|
||||
{
|
||||
byte ri = spriteOrder[ti + 8];
|
||||
rirq_move(ti, spriteYPos[ti + 1] + 23);
|
||||
|
||||
#ifdef VSPRITE_REVERSE
|
||||
char m = 0x80 >> (ti & 7);
|
||||
#else
|
||||
char m = 1 << (ti & 7);
|
||||
#endif
|
||||
|
||||
xymask |= m;
|
||||
if (!(vspriteXHigh[ri] & 1))
|
||||
xymask ^= m;
|
||||
|
||||
rirq_data(spirq + ti, 2, spriteYPos[ti + 9]);
|
||||
rirq_data(spirq + ti, 0, vspriteColor[ri]);
|
||||
rirq_data(spirq + ti, 1, vspriteXLow[ri]);
|
||||
rirq_data(spirq + ti, 3, vspriteImage[ri]);
|
||||
|
||||
rirq_data(spirq + ti, 4, xymask);
|
||||
// spriteYPos[ti + 9] = vspriteYLow[ri];
|
||||
}
|
||||
else
|
||||
{
|
||||
rirq_clear(ti);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma native(vspr_update)
|
||||
@@ -0,0 +1,113 @@
|
||||
#ifndef SPRITES_H
|
||||
#define SPRITES_H
|
||||
|
||||
#include "vic.h"
|
||||
|
||||
// initialize non virtualized sprite system, using only the eight hardware sprites
|
||||
|
||||
void spr_init(char * screen);
|
||||
|
||||
// set one sprite with the given attributes
|
||||
|
||||
void spr_set(char sp, bool show, int xpos, int ypos, char image, char color, bool multi, bool xexpand, bool yexpand);
|
||||
|
||||
// show or hide a sprite
|
||||
|
||||
inline void spr_show(char sp, bool show);
|
||||
|
||||
// move a sprite to the given position, only uses 8 bit y and 9 bit x
|
||||
|
||||
inline void spr_move(char sp, int xpos, int ypos);
|
||||
|
||||
// get current x position of sprite
|
||||
|
||||
inline int spr_posx(char sp);
|
||||
|
||||
// get current y position of sprite
|
||||
|
||||
inline int spr_posy(char sp);
|
||||
|
||||
// move a sprite to the given position, only uses 16 bit y and 16 bit x,
|
||||
// moves the sprite to a zero y position if offscreen
|
||||
void spr_move16(char sp, int xpos, int ypos);
|
||||
|
||||
// change the image of a sprite
|
||||
|
||||
inline void spr_image(char sp, char image);
|
||||
|
||||
// change the color of a sprite
|
||||
|
||||
inline void spr_color(char sp, char color);
|
||||
|
||||
// change the image of a sprite
|
||||
|
||||
inline void spr_expand(char sp, bool xexpand, bool yexpand);
|
||||
|
||||
// The virtual sprite system works with the rasterirq library to multiplex
|
||||
// 16 virtual sprites onto the actual eight hardware sprites. It uses the slots
|
||||
// 0 to 8 of the rasterirq library to switch the sprites mid screen. The
|
||||
// application has to race the beam and call at least the vspr_update every
|
||||
// bottom of the frame to reset the top eight sprites.
|
||||
//
|
||||
// A usual frame would look like this:
|
||||
//
|
||||
// - off screen game code
|
||||
// vspr_sort();
|
||||
// - more game code
|
||||
// rirq_wait();
|
||||
// vspr_update();
|
||||
// - more raster irq stuff
|
||||
// rirq_sort();
|
||||
//
|
||||
|
||||
#ifndef VSPRITES_MAX
|
||||
#define VSPRITES_MAX 16
|
||||
#endif
|
||||
|
||||
// initialize the virtual (multiplexed) sprite system, offering 16 sprites
|
||||
|
||||
void vspr_init(char * screen);
|
||||
|
||||
void vspr_shutdown(void);
|
||||
|
||||
void vspr_screen(char * screen);
|
||||
|
||||
// set one sprite with the given attribute
|
||||
|
||||
void vspr_set(char sp, int xpos, int ypos, char image, char color);
|
||||
|
||||
// move a virtual sprite
|
||||
|
||||
inline void vspr_move(char sp, int xpos, int ypos);
|
||||
|
||||
inline void vspr_movex(char sp, int xpos);
|
||||
|
||||
inline void vspr_movey(char sp, int ypos);
|
||||
|
||||
|
||||
// change the image of a virtual sprite
|
||||
|
||||
inline void vspr_image(char sp, char image);
|
||||
|
||||
// change the color of a virtual sprite
|
||||
|
||||
inline void vspr_color(char sp, char color);
|
||||
|
||||
// hide a virtual sprite, show again by moving it into the visual range
|
||||
|
||||
inline void vspr_hide(char sp);
|
||||
|
||||
|
||||
// sort the virtual sprites by their y-position
|
||||
|
||||
void vspr_sort(void);
|
||||
|
||||
// update the virtual sprites. Must be called every frame before sorting
|
||||
// the raster irq list.
|
||||
|
||||
void vspr_update(void);
|
||||
|
||||
|
||||
#pragma compile("sprites.c")
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef C64_TYPES_H
|
||||
#define C64_TYPES_H
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned int word;
|
||||
typedef unsigned long dword;
|
||||
|
||||
typedef signed char sbyte;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "vic.h"
|
||||
#include "cia.h"
|
||||
|
||||
void vic_setbank(char bank)
|
||||
{
|
||||
cia2.pra = (cia2.pra & 0xfc) | (bank ^ 0x03);
|
||||
}
|
||||
|
||||
void vic_sprxy(byte s, int x, int y)
|
||||
{
|
||||
vic.spr_pos[s].y = y;
|
||||
vic.spr_pos[s].x = x & 0xff;
|
||||
if (x & 0x100)
|
||||
vic.spr_msbx |= 1 << s;
|
||||
else
|
||||
vic.spr_msbx &= ~(1 << s);
|
||||
}
|
||||
|
||||
int vic_sprgetx(byte s)
|
||||
{
|
||||
return vic.spr_pos[s].x | ((vic.spr_msbx & (1 << s)) ? 256 : 0);
|
||||
}
|
||||
|
||||
void vic_setmode(VicMode mode, const char * text, const char * font)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case VICM_TEXT:
|
||||
vic.ctrl1 = VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3;
|
||||
vic.ctrl2 = VIC_CTRL2_CSEL;
|
||||
break;
|
||||
case VICM_TEXT_MC:
|
||||
vic.ctrl1 = VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3;
|
||||
vic.ctrl2 = VIC_CTRL2_CSEL | VIC_CTRL2_MCM;
|
||||
break;
|
||||
case VICM_TEXT_ECM:
|
||||
vic.ctrl1 = VIC_CTRL1_DEN | VIC_CTRL1_ECM | VIC_CTRL1_RSEL | 3;
|
||||
vic.ctrl2 = VIC_CTRL2_CSEL;
|
||||
break;
|
||||
case VICM_HIRES:
|
||||
vic.ctrl1 = VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3;
|
||||
vic.ctrl2 = VIC_CTRL2_CSEL;
|
||||
break;
|
||||
case VICM_HIRES_MC:
|
||||
vic.ctrl1 = VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3;
|
||||
vic.ctrl2 = VIC_CTRL2_CSEL | VIC_CTRL2_MCM;
|
||||
break;
|
||||
default:
|
||||
__assume(false);
|
||||
}
|
||||
|
||||
cia2.pra = (cia2.pra & 0xfc) | (((unsigned)text >> 14) ^ 0x03);
|
||||
vic.memptr = (((unsigned)text >> 6) & 0xf0) | (((unsigned)font >> 10) & 0x0e);
|
||||
}
|
||||
|
||||
bool vic_isBottom(void)
|
||||
{
|
||||
return (vic.ctrl1 & VIC_CTRL1_RST8) != 0;
|
||||
}
|
||||
|
||||
|
||||
void vic_waitBottom(void)
|
||||
{
|
||||
while (!(vic.ctrl1 & VIC_CTRL1_RST8))
|
||||
;
|
||||
}
|
||||
|
||||
void vic_waitTop(void)
|
||||
{
|
||||
while ((vic.ctrl1 & VIC_CTRL1_RST8))
|
||||
;
|
||||
}
|
||||
|
||||
void vic_waitFrame(void)
|
||||
{
|
||||
while ((vic.ctrl1 & VIC_CTRL1_RST8))
|
||||
;
|
||||
while (!(vic.ctrl1 & VIC_CTRL1_RST8))
|
||||
;
|
||||
}
|
||||
|
||||
void vic_waitFrames(char n)
|
||||
{
|
||||
while (n > 0)
|
||||
{
|
||||
vic_waitFrame();
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
void vic_waitLine(int line)
|
||||
{
|
||||
char upper = (char)(line >> 1) & VIC_CTRL1_RST8;
|
||||
char lower = (char)line;
|
||||
|
||||
do
|
||||
{
|
||||
while (vic.raster != lower)
|
||||
;
|
||||
} while ((vic.ctrl1 & VIC_CTRL1_RST8) != upper);
|
||||
}
|
||||
|
||||
void vic_waitBelow(int line)
|
||||
{
|
||||
char upper = (char)(line >> 1) & VIC_CTRL1_RST8;
|
||||
char lower = (char)line;
|
||||
|
||||
if (upper)
|
||||
{
|
||||
do
|
||||
{
|
||||
while (vic.raster <= lower)
|
||||
;
|
||||
} while (!(vic.ctrl1 & VIC_CTRL1_RST8));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (vic.raster <= lower)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void vic_waitRange(char below, char above)
|
||||
{
|
||||
while (vic.ctrl1 & VIC_CTRL1_RST8)
|
||||
;
|
||||
|
||||
if (vic.raster >= above)
|
||||
{
|
||||
while (!(vic.ctrl1 & VIC_CTRL1_RST8))
|
||||
;
|
||||
while (vic.ctrl1 & VIC_CTRL1_RST8)
|
||||
;
|
||||
}
|
||||
|
||||
while (vic.raster < below)
|
||||
;
|
||||
}
|
||||
|
||||
#pragma native(vic_waitLine)
|
||||
@@ -0,0 +1,135 @@
|
||||
#ifndef C64_VIC_H
|
||||
#define C64_VIC_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define VIC_CTRL1_RSEL 0x08
|
||||
#define VIC_CTRL1_DEN 0x10
|
||||
#define VIC_CTRL1_BMM 0x20
|
||||
#define VIC_CTRL1_ECM 0x40
|
||||
#define VIC_CTRL1_RST8 0x80
|
||||
|
||||
#define VIC_CTRL2_CSEL 0x08
|
||||
#define VIC_CTRL2_MCM 0x10
|
||||
#define VIC_CTRL2_RES 0x20
|
||||
|
||||
#define VIC_INTR_RST 0x01
|
||||
#define VIC_INTR_MBC 0x02
|
||||
#define VIC_INTR_MMC 0x04
|
||||
#define VIC_INTR_ILP 0x08
|
||||
#define VIC_INTR_IRQ 0x80
|
||||
|
||||
enum VICColors
|
||||
{
|
||||
VCOL_BLACK,
|
||||
VCOL_WHITE,
|
||||
VCOL_RED,
|
||||
VCOL_CYAN,
|
||||
VCOL_PURPLE,
|
||||
VCOL_GREEN,
|
||||
VCOL_BLUE,
|
||||
VCOL_YELLOW,
|
||||
|
||||
VCOL_ORANGE,
|
||||
VCOL_BROWN,
|
||||
VCOL_LT_RED,
|
||||
VCOL_DARK_GREY,
|
||||
VCOL_MED_GREY,
|
||||
VCOL_LT_GREEN,
|
||||
VCOL_LT_BLUE,
|
||||
VCOL_LT_GREY
|
||||
};
|
||||
|
||||
struct VIC
|
||||
{
|
||||
struct XY
|
||||
{
|
||||
volatile byte x, y;
|
||||
} spr_pos[8];
|
||||
byte spr_msbx;
|
||||
|
||||
volatile byte ctrl1;
|
||||
volatile byte raster;
|
||||
volatile byte lpx, lpy;
|
||||
volatile byte spr_enable;
|
||||
volatile byte ctrl2;
|
||||
volatile byte spr_expand_y;
|
||||
volatile byte memptr;
|
||||
volatile byte intr_ctrl;
|
||||
volatile byte intr_enable;
|
||||
volatile byte spr_priority;
|
||||
volatile byte spr_multi;
|
||||
volatile byte spr_expand_x;
|
||||
volatile byte spr_sprcol;
|
||||
volatile byte spr_backcol;
|
||||
volatile byte color_border;
|
||||
volatile byte color_back;
|
||||
volatile byte color_back1;
|
||||
volatile byte color_back2;
|
||||
volatile byte color_back3;
|
||||
volatile byte spr_mcolor0;
|
||||
volatile byte spr_mcolor1;
|
||||
volatile byte spr_color[8];
|
||||
|
||||
volatile byte ext_keymap;
|
||||
volatile byte ext_2mhz;
|
||||
volatile byte ext_uturbo;
|
||||
};
|
||||
|
||||
// set the 16k Bank for the vic
|
||||
// 0 : 0x0000..0x3fff
|
||||
// 1 : 0x4000..0x7fff
|
||||
// 2 : 0x8000..0xbfff
|
||||
// 3 : 0xc000..0xffff
|
||||
void vic_setbank(char bank);
|
||||
|
||||
enum VicMode
|
||||
{
|
||||
VICM_TEXT,
|
||||
VICM_TEXT_MC,
|
||||
VICM_TEXT_ECM,
|
||||
VICM_HIRES,
|
||||
VICM_HIRES_MC
|
||||
};
|
||||
|
||||
// set the display mode and base address. This will also
|
||||
// adapt the bank.
|
||||
void vic_setmode(VicMode mode, const char * text, const char * font);
|
||||
|
||||
// put a sprite at the given x/y location, taking care of the
|
||||
// x MSB
|
||||
inline void vic_sprxy(byte s, int x, int y);
|
||||
|
||||
// Read the sprite x position from the LSB and MSB register
|
||||
inline int vic_sprgetx(byte s);
|
||||
|
||||
// wait for the beam to reach the bottom of the visual area
|
||||
inline void vic_waitBottom(void);
|
||||
|
||||
// wait for the beam to reach the top of the frame
|
||||
inline void vic_waitTop(void);
|
||||
|
||||
// wait for the top of the frame and then for the bottom of the visual area
|
||||
inline void vic_waitFrame(void);
|
||||
|
||||
// return true if the beam is below the frame
|
||||
inline bool vic_isBottom(void);
|
||||
|
||||
// wait for n frames
|
||||
void vic_waitFrames(char n);
|
||||
|
||||
// wait for a specific raster line
|
||||
void vic_waitLine(int line);
|
||||
|
||||
// wait for beam to be below a line
|
||||
void vic_waitBelow(int line);
|
||||
|
||||
// wait for beam to be in a given range on screen
|
||||
void vic_waitRange(char below, char above);
|
||||
|
||||
// reference to the VIC chip
|
||||
#define vic (*((struct VIC *)0xd000))
|
||||
|
||||
#pragma compile("vic.c")
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user