initial commit

This commit is contained in:
2026-07-18 20:34:55 +02:00
commit 59ad004c96
474 changed files with 226635 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
#include "assert.h"
#include <stdlib.h>
void assert(bool b)
{
if (!b)
exit(-1);
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef ASSERT_H
#define ASSERT_H
void assert(bool b);
#pragma compile("assert.c")
#endif
+201
View File
@@ -0,0 +1,201 @@
#include "sidfx.h"
enum SIDFXState
{
SIDFX_IDLE,
SIDFX_RESET_0,
SIDFX_RESET_1,
SIDFX_READY,
SIDFX_PLAY,
SIDFX_WAIT
};
__striped static struct SIDFXChannel
{
const SIDFX * volatile com;
byte delay, priority;
volatile byte cnt;
volatile SIDFXState state;
unsigned freq, pwm;
} channels[3];
void sidfx_init(void)
{
for(char i=0; i<3; i++)
{
channels[i].com = nullptr;
channels[i].state = SIDFX_IDLE;
channels[i].priority = 0;
channels[i].delay = 1;
}
}
bool sidfx_idle(byte chn)
{
return channels[chn].state == SIDFX_IDLE;
}
char sidfx_cnt(byte chn)
{
return channels[chn].cnt;
}
void sidfx_play(byte chn, const SIDFX * fx, byte cnt)
{
SIDFXState ns = channels[chn].state;
if (ns == SIDFX_IDLE)
ns = SIDFX_READY;
else if (channels[chn].priority <= fx->priority)
ns = SIDFX_RESET_1;
else
return;
channels[chn].state = SIDFX_IDLE;
channels[chn].delay = 1;
channels[chn].com = fx;
channels[chn].cnt = cnt - 1;
channels[chn].priority = fx->priority;
channels[chn].state = ns;
}
void sidfx_stop(byte chn)
{
channels[chn].com = nullptr;
if (channels[chn].state != SIDFX_IDLE)
{
channels[chn].state = SIDFX_RESET_0;
channels[chn].delay = 1;
}
}
inline void sidfx_loop_ch(byte ch)
{
if (channels[ch].state)
{
const SIDFX * com = channels[ch].com;
channels[ch].delay--;
if (channels[ch].delay)
{
if (com->dfreq)
{
channels[ch].freq += com->dfreq;
sid.voices[ch].freq = channels[ch].freq;
}
if (com->dpwm)
{
channels[ch].pwm += com->dpwm;
sid.voices[ch].pwm = channels[ch].pwm;
}
}
while (!channels[ch].delay)
{
switch (channels[ch].state)
{
case SIDFX_IDLE:
channels[ch].delay = 1;
break;
case SIDFX_RESET_0:
sid.voices[ch].ctrl = 0;
sid.voices[ch].attdec = 0;
sid.voices[ch].susrel = 0;
if (com)
channels[ch].state = SIDFX_READY;
else
channels[ch].state = SIDFX_IDLE;
channels[ch].delay = 1;
break;
case SIDFX_RESET_1:
sid.voices[ch].ctrl = SID_CTRL_TEST;
sid.voices[ch].ctrl = 0;
sid.voices[ch].attdec = 0;
sid.voices[ch].susrel = 0;
channels[ch].state = SIDFX_READY;
break;
case SIDFX_READY:
channels[ch].freq = com->freq;
channels[ch].pwm = com->pwm;
sid.voices[ch].freq = com->freq;
sid.voices[ch].pwm = com->pwm;
sid.voices[ch].attdec = com->attdec;
sid.voices[ch].susrel = com->susrel;
sid.voices[ch].ctrl = com->ctrl;
if (com->ctrl & SID_CTRL_GATE)
{
channels[ch].delay = com->time1;
channels[ch].state = SIDFX_PLAY;
}
else
{
channels[ch].delay = com->time0;
channels[ch].state = SIDFX_PLAY;
}
break;
case SIDFX_PLAY:
if (com->time0)
{
sid.voices[ch].ctrl = com->ctrl & ~SID_CTRL_GATE;
channels[ch].delay = com->time0 - 1;
channels[ch].state = SIDFX_WAIT;
}
else if (channels[ch].cnt)
{
char sr = com->susrel & 0xf0;
com++;
char ctrl = com->ctrl;
if ((com->attdec & 0xef) == 0 && (ctrl & SID_CTRL_GATE) && (com->susrel & 0xf0) > sr)
{
sid.voices[ch].ctrl = ctrl & ~SID_CTRL_GATE;
sid.voices[ch].ctrl = ctrl | SID_CTRL_GATE;
}
channels[ch].cnt--;
channels[ch].com = com;
channels[ch].priority = com->priority;
channels[ch].state = SIDFX_READY;
}
else
{
com = nullptr;
channels[ch].state = SIDFX_RESET_0;
}
break;
case SIDFX_WAIT:
if (channels[ch].cnt)
{
com++;
channels[ch].cnt--;
channels[ch].com = com;
channels[ch].priority = com->priority;
if (com->ctrl & SID_CTRL_GATE)
channels[ch].state = SIDFX_RESET_0;
else
channels[ch].state = SIDFX_READY;
}
else
{
com = nullptr;
channels[ch].state = SIDFX_RESET_0;
}
break;
}
}
}
}
void sidfx_loop_2(void)
{
sidfx_loop_ch(2);
}
void sidfx_loop(void)
{
for(byte ch=0; ch<3; ch++)
sidfx_loop_ch(ch);
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef SIDFX_H
#define SIDFX_H
#include <c64/sid.h>
struct SIDFX
{
unsigned freq, pwm;
byte ctrl, attdec, susrel;
int dfreq, dpwm;
byte time1, time0;
byte priority;
};
void sidfx_init(void);
inline bool sidfx_idle(byte chn);
inline void sidfx_play(byte chn, const SIDFX * fx, byte cnt);
void sidfx_stop(byte chn);
char sidfx_cnt(byte chn);
void sidfx_loop(void);
void sidfx_loop_2(void);
#pragma compile("sidfx.c")
#endif
+84
View File
@@ -0,0 +1,84 @@
#include "bank1.h"
#include "mmu.h"
#include <string.h>
void bnk1_init(void)
{
mmu.cr = 0x3e;
memcpy((char *)0xfc00, (char *)0xf000, 0x0300);
xmmu.rcr |= 0x0c;
mmu.cr = 0x3f;
}
#pragma code(bnk1code)
char bnk1_readb(volatile char * p)
{
mmu.bank1 = 0;
char c = *p;
mmu.bank0 = 0;
return c;
}
unsigned bnk1_readw(volatile unsigned * p)
{
mmu.bank1 = 0;
unsigned w = *p;
mmu.bank0 = 1;
return w;
}
unsigned long bnk1_readl(volatile unsigned long * p)
{
mmu.bank1 = 0;
unsigned long l = *p;
mmu.bank0 = 3;
return l;
}
void bnk1_readm(char * dp, volatile char * sp, unsigned size)
{
while (size > 0)
{
mmu.bank1 = 0;
char c = * sp++;
mmu.bank0 = c;
*dp++ = c;
size--;
}
}
void bnk1_writeb(volatile char * p, char b)
{
mmu.bank1 = b;
*p = b;
mmu.bank0 = b;
}
void bnk1_writew(volatile unsigned * p, unsigned w)
{
mmu.bank1 = w;
*p = w;
mmu.bank0 = w;
}
void bnk1_writel(volatile unsigned long * p, unsigned long l)
{
mmu.bank1 = l;
*p = l;
mmu.bank0 = l;
}
void bnk1_writem(volatile char * dp, const char * sp, unsigned size)
{
while (size > 0)
{
char c = * sp++;
mmu.bank1 = c;
*dp++ = c;
mmu.bank0 = c;
size--;
}
}
#pragma code(code)
+34
View File
@@ -0,0 +1,34 @@
#ifndef C128_BANK1_H
#define C128_BANK1_H
#pragma section( bnk1code, 0)
#pragma region( bnk1code, 0xf000, 0xf300, , , {bnk1code}, 0xfc00 )
void bnk1_init(void);
#pragma code(bnk1code)
__noinline char bnk1_readb(volatile char * p);
__noinline unsigned bnk1_readw(volatile unsigned * p);
__noinline unsigned long bnk1_readl(volatile unsigned long * p);
__noinline void bnk1_readm(char * dp, volatile char * sp, unsigned size);
__noinline void bnk1_writeb(volatile char * p, char b);
__noinline void bnk1_writew(volatile unsigned * p, unsigned w);
__noinline void bnk1_writel(volatile unsigned long * p, unsigned long l);
__noinline void bnk1_writem(volatile char * dp, const char * sp, unsigned size);
#pragma code(code)
#pragma compile("bank1.c")
#endif
+8
View File
@@ -0,0 +1,8 @@
#include "mmu.h"
inline char mmu_set(char cr)
{
char pcr = mmu.cr;
mmu.cr = cr;
return pcr;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef C128_MMU_H
#define C128_MMU_H
#include <c64/types.h>
struct MMU
{
volatile __memmap byte cr;
volatile __memmap byte bank0;
volatile __memmap byte bank1;
volatile __memmap byte bank14;
volatile __memmap byte bankx;
};
struct XMMU
{
volatile byte cr;
volatile byte pcr[4];
volatile byte mcr;
volatile byte rcr;
volatile word page0;
volatile word page1;
volatile byte vr;
};
#define mmu (*((struct MMU *)0xff00))
#define xmmu (*((struct XMMU *)0xd500))
inline char mmu_set(char cr);
#pragma compile("mmu.c")
#endif
+84
View File
@@ -0,0 +1,84 @@
#include "vdc.h"
inline void vdc_reg(VDCRegister reg)
{
vdc.addr = reg;
}
inline void vdc_write(byte data)
{
do {} while (vdc.addr < 128);
vdc.data = data;
}
inline byte vdc_read(void)
{
do {} while (vdc.addr < 128);
return vdc.data;
}
void vdc_reg_write(VDCRegister reg, byte data)
{
vdc_reg(reg);
vdc_write(data);
}
byte vdc_reg_read(VDCRegister reg)
{
vdc_reg(reg);
return vdc_read();
}
void vdc_mem_addr(unsigned addr)
{
#pragma callinline()
vdc_reg_write(VDCR_ADDRH, addr >> 8);
#pragma callinline()
vdc_reg_write(VDCR_ADDRL, addr);
#pragma callinline()
vdc_reg(VDCR_DATA);
}
inline void vdc_mem_write(char data)
{
vdc_write(data);
}
inline char vdc_mem_read(void)
{
return vdc_read();
}
void vdc_mem_write_at(unsigned addr, char data)
{
#pragma callinline()
vdc_mem_addr(addr);
vdc_write(data);
}
char vdc_mem_read_at(unsigned addr)
{
#pragma callinline()
vdc_mem_addr(addr);
return vdc_read();
}
void vdc_mem_write_buffer(unsigned addr, const char * data, char size)
{
vdc_mem_addr(addr);
for(char i=0; i<size; i++)
vdc_write(data[i]);
}
void vdc_mem_read_buffer(unsigned addr, char * data, char size)
{
vdc_mem_addr(addr);
for(char i=0; i<size; i++)
data[i] = vdc_read();
}
+95
View File
@@ -0,0 +1,95 @@
#ifndef C128_VDC_H
#define C128_VDC_H
#include <c64/types.h>
enum VDCRegister
{
VDCR_HTOTAL,
VDCR_HDISPLAY,
VDCR_HSYNC,
VDCR_SYNCSIZE,
VDCR_VTOTAL,
VDCR_VADJUST,
VDCR_VDISPLAY,
VDCR_VSYNC,
VDCR_LACE,
VDCR_CSIZE,
VDCR_CURSOR_START,
VDCR_CURSOR_END,
VDCR_DISP_ADDRH,
VDCR_DISP_ADDRL,
VDCR_CURSOR_ADDRH,
VDCR_CURSOR_ADDRL,
VDCR_LPEN_Y,
VDCR_LPEN_X,
VDCR_ADDRH,
VDCR_ADDRL,
VDCR_ATTR_ADDRH,
VDCR_ATTR_ADDRL,
VDCR_CWIDTH,
VDCR_CHEIGHT,
VDCR_VSCROLL,
VDCR_HSCROLL,
VDCR_COLOR,
VDCR_ROWINC,
VDCR_CHAR_ADDRH,
VDCR_UNDERLINE,
VDCR_DSIZE,
VDCR_DATA,
VDCR_BLOCK_ADDRH,
VDCR_BLOCK_ADDRL,
VDCR_HSTART,
VDCR_HEND,
VDCR_REFRESH
};
struct VDC
{
volatile char addr;
volatile char data;
};
#define vdc (*((struct VDC *)0xd600))
inline void vdc_reg(VDCRegister reg);
inline void vdc_write(byte data);
inline byte vdc_read(void);
void vdc_reg_write(VDCRegister reg, byte data);
byte vdc_reg_read(VDCRegister reg);
void vdc_mem_addr(unsigned addr);
inline void vdc_mem_write(char data);
inline char vdc_mem_read(void);
void vdc_mem_write_at(unsigned addr, char data);
char vdc_mem_read_at(unsigned addr);
void vdc_mem_write_buffer(unsigned addr, const char * data, char size);
void vdc_mem_read_buffer(unsigned addr, char * data, char size);
#pragma compile("vdc.c")
#endif
+94
View File
@@ -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;
}
+132
View File
@@ -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
+985
View File
@@ -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);
}
+211
View File
@@ -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
+26
View File
@@ -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;
}
+29
View File
@@ -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
+63
View File
@@ -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
+608
View File
@@ -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;
}
+79
View File
@@ -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
+353
View File
@@ -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)
+43
View File
@@ -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
+25
View File
@@ -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;
}
+17
View File
@@ -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
+541
View File
@@ -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)
+102
View File
@@ -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
+100
View File
@@ -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;
}
+134
View File
@@ -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
+82
View File
@@ -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;
}
+34
View File
@@ -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
+52
View File
@@ -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();
}
+26
View File
@@ -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
+716
View File
@@ -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)
+202
View File
@@ -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
+97
View File
@@ -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;
}
}
+68
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
#include "sid.h"
+107
View File
@@ -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
+346
View File
@@ -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)
+113
View File
@@ -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
+10
View File
@@ -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
+140
View File
@@ -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)
+135
View File
@@ -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
+426
View File
@@ -0,0 +1,426 @@
#include "conio.h"
static IOCharMap giocharmap = IOCHM_ASCII;
#if defined(__C128__)
#pragma code(lowcode)
__asm bsout
{
ldx #0
stx 0xff00
jsr 0xffd2
sta 0xff01
}
__asm bsin
{
lda #0
sta 0xff00
jsr 0xffe4
sta 0xff01
}
__asm bsget
{
lda #0
sta 0xff00
jsr 0xffcf
sta 0xff01
}
__asm bsplot
{
lda #0
sta 0xff00
jsr 0xfff0
sta 0xff01
}
__asm bsinit
{
lda #0
sta 0xff00
jsr 0xff81
sta 0xff01
}
__asm dswap
{
sta 0xff00
jsr 0xff5f
sta 0xff01
}
#pragma code(code)
#elif defined(__C128B__) || defined(__C128E__)
#define dswap 0xff5f
#define bsout 0xffd2 : a->a
#define bsin 0xffe4
#define bsget 0xffcf : a->a
#define bsplot 0xfff0
#define bsinit 0xff81
#elif defined(__PLUS4__)
#pragma code(lowcode)
__asm bsout
{
sta 0xff3e
jsr 0xffd2
sta 0xff3f
}
__asm bsin
{
sta 0xff3e
jsr 0xffe4
sta 0xff3f
}
__asm bsget
{
sta 0xff3e
jsr 0xffcf
sta 0xff3f
}
__asm bsplot
{
sta 0xff3e
jsr 0xfff0
sta 0xff3f
}
__asm bsinit
{
sta 0xff3e
jsr 0xff81
sta 0xff3f
}
#pragma code(code)
#elif defined(__ATARI__)
__asm bsout
{
tax
lda 0xe407
pha
lda 0xe406
pha
txa
}
__asm bsin
{
lda 0xe405
pha
lda 0xe404
pha
}
__asm bsget
{
lda 0xe405
pha
lda 0xe404
pha
}
__asm bsplot
{
}
__asm bsinit
{
}
#elif defined(__VIC20__)
#define bsout 0xffd2 : a->a
#define bsin 0xffe4
#define bsplot 0xfff0
#define bsget 0xffcf : a->a
__asm bsinit
{
lda #147
jmp $ffd2
}
#elif defined(__CBMPET__)
#define bsout 0xffd2 : a->a
#define bsin 0xffe4
__asm bsplot
{
/* no equivalent on PET */
}
__asm bsinit
{
/* no equivalent on PET */
}
#define bsget 0xffcf
#else
#define bsout 0xffd2 : a->a
#define bsin 0xffe4
#define bsplot 0xfff0
#define bsinit 0xff81
#define bsget 0xffcf : a->a
#endif
#if defined(__C128__) || defined(__C128B__) || defined(__C128E__)
void dispmode40col(void)
{
if (*(volatile char *)0xd7 >= 128)
{
__asm
{
jsr dswap
}
}
}
void dispmode80col(void)
{
if (*(volatile char *)0xd7 < 128)
{
__asm
{
jsr dswap
}
}
}
#endif
void iocharmap(IOCharMap chmap)
{
giocharmap = chmap;
#if !defined(__ATARI__)
if (chmap == IOCHM_PETSCII_1)
putrch(128 + 14);
else if (chmap == IOCHM_PETSCII_2)
putrch(14);
#endif
}
void putrch(char c)
{
__asm {
lda c
jsr bsout
}
}
void putpch(char c)
{
#if defined(__ATARI__)
if (c == 10)
c = 0x9b;
#else
if (giocharmap >= IOCHM_ASCII)
{
if (c == '\n')
c = 13;
else if (c == '\t')
{
char n = wherex() & 3;
do {
putrch(' ');
} while (++n < 4);
return;
}
else if (giocharmap >= IOCHM_PETSCII_1)
{
if (c >= 65 && c < 123)
{
if (c >= 97 || c < 91)
{
#if defined(__CBMPET__)
if (c >= 97)
c ^= 0xa0;
c ^= 0x20;
#else
c ^= 0x20;
#endif
if (giocharmap == IOCHM_PETSCII_1)
c &= 0xdf;
}
}
}
}
#endif
putrch(c);
}
static char convch(char ch)
{
#if !defined(__ATARI__)
if (giocharmap >= IOCHM_ASCII)
{
if (ch == 13)
ch = 10;
else if (giocharmap >= IOCHM_PETSCII_1)
{
if (ch >= 65 && ch < 219)
{
if (ch >= 193)
ch ^= 0xa0;
if (ch < 123 && (ch >= 97 || ch < 91))
ch ^= 0x20;
}
}
}
#endif
return ch;
}
char getrch(void)
{
return __asm {
jsr bsget
sta accu
};
}
char getpch(void)
{
return convch(getrch());
}
char kbhit(void)
{
#if defined(__CBMPET__)
return __asm
{
lda $9e
sta accu
};
#else
return __asm
{
lda $c6
sta accu
};
#endif
}
char getche(void)
{
char ch;
do {
ch = __asm {
jsr bsin
sta accu
};
} while (!ch);
__asm {
lda ch
jsr bsout
}
return convch(ch);
}
char getch(void)
{
char ch;
do {
ch = __asm {
jsr bsin
sta accu
};
} while (!ch);
return convch(ch);
}
char getchx(void)
{
char ch = __asm {
jsr bsin
sta accu
};
return convch(ch);
}
void putch(char c)
{
putpch(c);
}
void clrscr(void)
{
putrch(147);
}
void textcursor(bool show)
{
*(volatile char *)0xcc = show ? 0 : 1;
}
void gotoxy(char cx, char cy)
{
#if defined(__CBMPET__)
#define CURS_X 0xc6
#define CURS_Y 0xd8
#define SCREEN_PTR 0xc4
#define SCR_LINELEN 0xd5
__assume(cy < 25);
*(volatile char *)CURS_X = cx;
*(volatile char *)CURS_Y = cy;
if (*(volatile char *)SCR_LINELEN > 40)
cy <<= 1;
const unsigned off = cy * 40;
* (volatile unsigned *)SCREEN_PTR = off + 0x8000;
#else
__asm
{
ldx cy
ldy cx
clc
jsr bsplot
}
#endif
}
void textcolor(char c)
{
*(volatile char *)0x0286 = c;
}
void bgcolor(char c)
{
*(volatile char *)0xd021 = c;
}
void bordercolor(char c)
{
*(volatile char *)0xd020 = c;
}
void revers(char r)
{
if (r)
putrch(18);
else
putrch(18 + 128);
}
char wherex(void)
{
#if defined(__C128__) || defined(__C128B__) || defined(__C128E__)
return *(volatile char *)0xec;
#elif defined(__PLUS4__)
return *(volatile char *)0xca;
#else
return *(volatile char *)0xd3;
#endif
}
char wherey(void)
{
#if defined(__C128__) || defined(__C128B__) || defined(__C128E__)
return *(volatile char *)0xeb;
#elif defined(__PLUS4__)
return *(volatile char *)0xcd;
#else
return *(volatile char *)0xd6;
#endif
}
+114
View File
@@ -0,0 +1,114 @@
#ifndef CONIO_H
#define CONIO_H
enum IOCharMap
{
IOCHM_TRANSPARENT,
IOCHM_ASCII,
IOCHM_PETSCII_1,
IOCHM_PETSCII_2
};
extern IOCharMap giocharmap;
// Switch character map to transparent bypass, petscii font 1 or
// petscii font 2. Translation is performed for all reading and
// writing operations. The ascii mode will only translate the
// line end CR into an LF
void iocharmap(IOCharMap chmap);
#if defined(__C128__) || defined(__C128B__) || defined(__C128E__)
void dispmode40col(void);
void dispmode80col(void);
#endif
#define PETSCII_CURSOR_LEFT 0x9d
#define PETSCII_CURSOR_RIGHT 0x1d
#define PETSCII_CURSOR_UP 0x91
#define PETSCII_CURSOR_DOWN 0x11
#define PETSCII_HOME 0x13
#define PETSCII_CLEAR 0x94
#define PETSCII_DEL 0x14
#define PETSCII_INSERT 0x94
#define PETSCII_STOP 0x03
#define PETSCII_RETURN 0x0d
#define PETSCII_F1 0x85
#define PETSCII_F2 0x89
#define PETSCII_F3 0x86
#define PETSCII_F4 0x8a
#define PETSCII_F5 0x87
#define PETSCII_F6 0x8b
#define PETSCII_F7 0x88
#define PETSCII_F8 0x8c
enum ConioColors
{
COLOR_BLACK,
COLOR_WHITE,
COLOR_RED,
COLOR_CYAN,
COLOR_PURPLE,
COLOR_GREEN,
COLOR_BLUE,
COLOR_YELLOW,
COLOR_ORANGE,
COLOR_BROWN,
COLOR_LT_RED,
COLOR_DARK_GREY,
COLOR_MED_GREY,
COLOR_LT_GREEN,
COLOR_LT_BLUE,
COLOR_LT_GREY
};
// Lowlevel console in/out
// using petscii translation
void putpch(char c);
char getpch(void);
// using no translation
inline void putrch(char c);
inline char getrch(void);
// Standard console in/out
char kbhit(void);
char getche(void);
char getch(void);
// like getch but does not wait, returns zero if no
// key is pressed
char getchx(void);
void putch(char c);
void clrscr(void);
void gotoxy(char x, char y);
inline void textcolor(char c);
inline void bgcolor(char c);
inline void bordercolor(char c);
inline void revers(char r);
inline char wherex(void);
inline char wherey(void);
// show or hide the text cursor
inline void textcursor(bool show);
#pragma compile("conio.c")
#endif
File diff suppressed because it is too large Load Diff
+196
View File
@@ -0,0 +1,196 @@
#ifndef CRT_H
#define CRT_H
extern char spentry;
enum ByteCode
{
BC_NOP,
BC_EXIT,
BC_CONST_8,
BC_CONST_P8,
BC_CONST_N8,
BC_CONST_16,
BC_CONST_32,
BC_LOAD_REG_8,
BC_STORE_REG_8,
BC_LOAD_REG_16,
BC_STORE_REG_16,
BC_ADDR_REG,
BC_LOAD_REG_32,
BC_STORE_REG_32,
BC_LOAD_ABS_8,
BC_LOAD_ABS_U8,
BC_LOAD_ABS_16,
BC_LOAD_ABS_32,
BC_LOAD_ABS_ADDR,
BC_STORE_ABS_8,
BC_STORE_ABS_16,
BC_STORE_ABS_32,
BC_LEA_ABS,
BC_LEA_ABS_INDEX,
BC_LEA_ABS_INDEX_U8,
BC_LEA_ACCU_INDEX,
BC_LOAD_LOCAL_8,
BC_LOAD_LOCAL_U8,
BC_LOAD_LOCAL_16,
BC_LOAD_LOCAL_32,
BC_STORE_LOCAL_8,
BC_STORE_LOCAL_16,
BC_STORE_LOCAL_32,
BC_LEA_LOCAL,
BC_STORE_FRAME_8,
BC_STORE_FRAME_16,
BC_STORE_FRAME_32,
BC_LEA_FRAME,
BC_LOAD_ADDR_8,
BC_LOAD_ADDR_U8,
BC_LOAD_ADDR_16,
BC_LOAD_ADDR_32,
BC_STORE_ADDR_8,
BC_STORE_ADDR_16,
BC_STORE_ADDR_32,
BC_BINOP_ADDR_16,
BC_BINOP_SUBR_16,
BC_BINOP_ANDR_16,
BC_BINOP_ORR_16,
BC_BINOP_XORR_16,
BC_BINOP_MULR_16,
BC_BINOP_DIVR_U16,
BC_BINOP_MODR_U16,
BC_BINOP_DIVR_I16,
BC_BINOP_MODR_I16,
BC_BINOP_SHLR_16,
BC_BINOP_SHRR_U16,
BC_BINOP_SHRR_I16,
BC_BINOP_ADDA_16,
BC_BINOP_ADDI_16,
BC_BINOP_SUBI_16,
BC_BINOP_ANDI_16,
BC_BINOP_ORI_16,
BC_BINOP_MULI8_16,
BC_BINOP_ADDI_8,
BC_BINOP_ANDI_8,
BC_BINOP_ORI_8,
BC_BINOP_SHLI_16,
BC_BINOP_SHRI_U16,
BC_BINOP_SHRI_I16,
BC_BINOP_CMPUR_16,
BC_BINOP_CMPSR_16,
BC_BINOP_CMPUI_16,
BC_BINOP_CMPSI_16,
BC_BINOP_CMPUR_8,
BC_BINOP_CMPSR_8,
BC_BINOP_CMPUI_8,
BC_BINOP_CMPSI_8,
BC_OP_NEGATE_16,
BC_OP_INVERT_16,
BC_BINOP_ADD_F32,
BC_BINOP_SUB_F32,
BC_BINOP_MUL_F32,
BC_BINOP_DIV_F32,
BC_BINOP_CMP_F32,
BC_OP_NEGATE_F32,
BC_OP_ABS_F32,
BC_OP_FLOOR_F32,
BC_OP_CEIL_F32,
BC_CONV_U16_F32,
BC_CONV_I16_F32,
BC_CONV_F32_U16,
BC_CONV_F32_I16,
BC_CONV_I8_I16,
BC_JUMPS,
BC_BRANCHS_EQ,
BC_BRANCHS_NE,
BC_BRANCHS_GT,
BC_BRANCHS_GE,
BC_BRANCHS_LT,
BC_BRANCHS_LE,
BC_JUMPF,
BC_BRANCHF_EQ,
BC_BRANCHF_NE,
BC_BRANCHF_GT,
BC_BRANCHF_GE,
BC_BRANCHF_LT,
BC_BRANCHF_LE,
BC_LOOP_U8,
BC_MALLOC,
BC_FREE,
BC_FILL,
BC_FILL_LONG,
BC_UNUSED_6,
BC_JSR,
BC_NATIVE = 0x75,
BC_ENTER,
BC_RETURN,
BC_CALL_ADDR,
BC_CALL_ABS,
BC_PUSH_FRAME,
BC_POP_FRAME,
BC_COPY,
BC_COPY_LONG,
BC_STRCPY,
BC_EXTRT,
BC_CONV_I16_I32 = 0x80,
BC_CONV_U16_U32,
BC_OP_NEGATE_32,
BC_OP_INVERT_32,
BC_BINOP_ADD_L32,
BC_BINOP_SUB_L32,
BC_BINOP_AND_L32,
BC_BINOP_OR_L32,
BC_BINOP_XOR_L32,
BC_BINOP_MUL_L32,
BC_BINOP_DIV_U32,
BC_BINOP_MOD_U32,
BC_BINOP_DIV_I32,
BC_BINOP_MOD_I32,
BC_BINOP_SHL_L32,
BC_BINOP_SHR_U32,
BC_BINOP_SHR_I32,
BC_BINOP_CMP_U32,
BC_BINOP_CMP_S32,
BC_CONV_U32_F32,
BC_CONV_I32_F32,
BC_CONV_F32_U32,
BC_CONV_F32_I32,
};
#endif
+105
View File
@@ -0,0 +1,105 @@
#include "ctype.h"
#include "conio.h"
#define CC_CTRL 0x00
#define CC_BREAK 0x01
#define CC_SPACE 0x02
#define CC_DIGIT 0x04
#define CC_LOWER 0x08
#define CC_UPPER 0x10
#define CC_HEX 0x20
#define CC_PUNCT 0x40
static const char _cinfo[128] = {
[0 ... 8] = CC_CTRL,
[9] = CC_SPACE,
[10 ... 13] = CC_BREAK,
[14 ... 31] = CC_CTRL,
[32] = CC_SPACE,
[33 ... 47] = CC_PUNCT,
[48 ... 57] = CC_DIGIT,
[58 ... 64] = CC_PUNCT,
[65 ... 70] = CC_UPPER | CC_HEX,
[71 ... 90] = CC_UPPER,
[91 ... 96] = CC_PUNCT,
[97 ... 102] = CC_LOWER | CC_HEX,
[103 ... 122] = CC_LOWER,
[123 ... 126] = CC_PUNCT,
[127] = CC_CTRL
};
bool isctrnl(char c)
{
return (c < 128) && _cinfo[c] == CC_CTRL;
}
bool isprint(char c)
{
return (c < 128) && _cinfo[c] != CC_CTRL;
}
bool isspace(char c)
{
return (c < 128) && (_cinfo[c] & (CC_SPACE | CC_BREAK));
}
bool isblank(char c)
{
return (c < 128) && (_cinfo[c] & CC_SPACE);
}
bool isgraph(char c)
{
return (c < 128) && (_cinfo[c] & (CC_LOWER | CC_UPPER | CC_DIGIT | CC_PUNCT));
}
bool ispunct(char c)
{
return (c < 128) && (_cinfo[c] & CC_PUNCT);
}
bool isalnum(char c)
{
return (c < 128) && (_cinfo[c] & (CC_LOWER | CC_UPPER | CC_DIGIT));
}
bool isalpha(char c)
{
return (c < 128) && (_cinfo[c] & (CC_LOWER | CC_UPPER));
}
bool isupper(char c)
{
return (c < 128) && (_cinfo[c] & CC_UPPER);
}
bool islower(char c)
{
return (c < 128) && (_cinfo[c] & CC_LOWER);
}
bool isdigit(char c)
{
return (c < 128) && (_cinfo[c] & CC_DIGIT);
}
bool isxdigit(char c)
{
return (c < 128) && (_cinfo[c] & CC_HEX);
}
char tolower(char c)
{
if (c >= 'A' && c <= 'Z')
return c + ('a' - 'A');
else
return c;
}
char toupper(char c)
{
if (c >= 'a' && c <= 'z')
return c + ('A' - 'a');
else
return c;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef CTYPE_H
#define CTYPE_H
inline bool isctrnl(char c);
inline bool isprint(char c);
inline bool isspace(char c);
inline bool isblank(char c);
inline bool isgraph(char c);
inline bool ispunct(char c);
inline bool isalnum(char c);
inline bool isalpha(char c);
inline bool isupper(char c);
inline bool islower(char c);
inline bool isdigit(char c);
inline bool isxdigit(char c);
char tolower(char c);
char toupper(char c);
#pragma compile("ctype.c")
#endif
+166
View File
@@ -0,0 +1,166 @@
#include "vera.h"
void vram_addr(unsigned long addr)
{
vera.ctrl &= ~VERA_CTRL_ADDRSEL;
vera.addr = (unsigned)addr;
vera.addrh = (char)((addr >> 16) & 1) | 0x10;
}
void vram_addr0(unsigned long addr)
{
vera.ctrl &= ~VERA_CTRL_ADDRSEL;
vera.addr = (unsigned)addr;
vera.addrh = (char)((addr >> 16) & 1) | 0x00;
}
void vram_addr2(unsigned long addr)
{
vera.ctrl &= ~VERA_CTRL_ADDRSEL;
vera.addr = (unsigned)addr;
vera.addrh = (char)((addr >> 16) & 1) | 0x20;
}
void vram_put(char data)
{
vera.data0 = data;
}
void vram_putw(unsigned data)
{
vera.data0 = data & 0xff;
vera.data0 = data >> 8;
}
char vram_get(void)
{
return vera.data0;
}
unsigned vram_getw(void)
{
unsigned l = vera.data0;
unsigned h = vera.data0;
return (h << 8) | l;
}
void vram_put_at(unsigned long addr, char data)
{
vram_addr(addr);
vram_put(data);
}
char vram_get_at(unsigned long addr)
{
vram_addr(addr);
return vram_get();;
}
void vram_putn(unsigned long addr, const char * data, unsigned size)
{
vram_addr(addr);
while(size > 0)
{
vram_put(*data++);
size--;
}
}
void vram_getn(unsigned long addr, char * data, unsigned size)
{
vram_addr(addr);
while(size > 0)
{
*data++ = vram_get();
size--;
}
}
void vram_fill(unsigned long addr, char data, unsigned size)
{
vram_addr(addr);
while(size > 0)
{
vram_put(data);
size--;
}
}
void vera_spr_set(char spr, unsigned addr32, VERASpriteMode mode8, VERASpriteSize w, VERASpriteSize h, VERASpritePriority z, char pal)
{
__assume(spr < 128);
vram_addr(0x1fc00UL + spr * 8);
vram_putw(addr32 | (mode8 ? 0x8000 : 0x0000));
vram_putw(0);
vram_putw(0);
vram_put(z << 2);
vram_put((h << 6) | (w << 4) | pal);
}
void vera_spr_flip(char spr, bool fliph, bool flipv)
{
__assume(spr < 128);
vram_addr0(0x1fc00UL + spr * 8 + 6);
char b = vram_get() & 0xfc;
if (fliph) b |= 0x01;
if (flipv) b |= 0x02;
vram_put(b);
}
void vera_spr_move(char spr, int x, int y)
{
__assume(spr < 128);
vram_addr(0x1fc00UL + spr * 8 + 2);
vram_putw(x);
vram_putw(y);
}
void vera_spr_image(char spr, unsigned addr32)
{
__assume(spr < 128);
vram_addr(0x1fc00UL + spr * 8);
vram_put(addr32 & 0xff);
vera.addrh &= 0x0f;
char b = vram_get() & 0x80;
vram_put((addr32 >> 8) | b);
}
void vera_pal_put(char index, unsigned color)
{
vram_addr(0x1fa00ul + 2 * index);
vram_putw(color);
}
unsigned vera_pal_get(char index)
{
vram_addr(0x1fa00ul + 2 * index);
return vram_getw();
}
void vera_pal_putn(char index, const unsigned * color, unsigned size)
{
vram_addr(0x1fa00ul + 2 * index);
while (size > 0)
{
vram_putw(*color++);
size--;
}
}
void vera_pal_getn(char index, unsigned * color, unsigned size)
{
vram_addr(0x1fa00ul + 2 * index);
while (size > 0)
{
*color++ = vram_getw();
size--;
}
}
+157
View File
@@ -0,0 +1,157 @@
#ifndef CX16_VERA_H
#define CX16_VERA_H
// Thanks to crisps for providing the initial code for this library
#include <c64/types.h>
#define VERA_ADDRH_DECR 0x08
#define VERA_ADDRH_INC 0xf0
#define VERA_CTRL_RESET 0x80
#define VERA_CTRL_DCSEL 0x02
#define VERA_CTRL_ADDRSEL 0x01
#define VERA_IRQ_LINE_8 0x80
#define VERA_IRQ_AFLOW 0x08
#define VERA_IRQ_SPRCOL 0x04
#define VERA_IRQ_LINE 0x02
#define VERA_IRQ_VSYNC 0x01
#define VERA_DCVIDEO_MODE_OFF 0x00
#define VERA_DCVIDEO_MODE_VGA 0x01
#define VERA_DCVIDEO_MODE_NTSC 0x02
#define VERA_DCVIDEO_MODE_RGBI 0x03
#define VERA_DCVIDEO_NCHROMA 0x04
#define VERA_DCVIDEO_LAYER0 0x10
#define VERA_DCVIDEO_LAYER1 0x20
#define VERA_DCVIDEO_SPRITES 0x40
#define VERA_LAYER_DEPTH_1 0x00
#define VERA_LAYER_DEPTH_2 0x01
#define VERA_LAYER_DEPTH_4 0x02
#define VERA_LAYER_DEPTH_8 0x03
#define VERA_LAYER_BITMAP 0x04
#define VERA_LAYER_T256C 0x08
#define VERA_LAYER_WIDTH_32 0x00
#define VERA_LAYER_WIDTH_64 0x10
#define VERA_LAYER_WIDTH_128 0x20
#define VERA_LAYER_WIDTH_256 0x30
#define VERA_LAYER_HEIGHT_32 0x00
#define VERA_LAYER_HEIGHT_64 0x40
#define VERA_LAYER_HEIGHT_128 0x80
#define VERA_LAYER_HEIGHT_256 0xc0
#define VERA_TILE_WIDTH_8 0x00
#define VERA_TILE_WIDTH_16 0x01
#define VERA_TILE_HEIGHT_8 0x00
#define VERA_TILE_HEIGHT_16 0x02
struct VERA
{
volatile word addr;
volatile byte addrh;
volatile byte data0, data1;
volatile byte ctrl;
volatile byte ien;
volatile byte isr;
volatile byte irqline;
volatile byte dcvideo;
volatile byte dchscale;
volatile byte dcvscale;
volatile byte dcborder;
volatile byte l0config;
volatile byte l0mapbase;
volatile byte l0tilebase;
volatile word l0hscroll;
volatile word l0vscroll;
volatile byte l1config;
volatile byte l1mapbase;
volatile byte l1tilebase;
volatile word l1hscroll;
volatile word l1vscroll;
volatile byte audioctrl;
volatile byte audiorate;
volatile byte audiodata;
volatile byte spidata;
volatile byte spictrl;
};
enum VERASpriteMode
{
VSPRMODE_4,
VSPRMODE_8
};
enum VERASpriteSize
{
VSPRSZIZE_8,
VSPRSZIZE_16,
VSPRSZIZE_32,
VSPRSZIZE_64
};
enum VERASpritePriority
{
VSPRPRI_OFF,
VSPRPRI_BACK,
VSPRPRI_MIDDLE,
VSPRPRI_FRONT
};
#define VERA_COLOR(r, g, b) (((unsigned)(r) << 8) | ((unsigned)(g) << 4) | (unsigned)(b))
#define vera (*(VERA *)0x9f20)
inline void vram_addr(unsigned long addr);
inline void vram_addr0(unsigned long addr);
inline void vram_addr2(unsigned long addr);
inline void vram_put(char data);
inline void vram_putw(unsigned data);
inline char vram_get(void);
inline unsigned vram_getw(void);
inline void vram_put_at(unsigned long addr, char data);
inline char vram_get_at(unsigned long addr);
void vram_putn(unsigned long addr, const char * data, unsigned size);
void vram_getn(unsigned long addr, char * data, unsigned size);
void vram_fill(unsigned long addr, char data, unsigned size);
void vera_spr_set(char spr, unsigned addr32, VERASpriteMode mode8, VERASpriteSize w, VERASpriteSize h, VERASpritePriority z, char pal);
void vera_spr_flip(char spr, bool fliph, bool flipv);
void vera_spr_move(char spr, int x, int y);
void vera_spr_image(char spr, unsigned addr32);
void vera_pal_put(char index, unsigned color);
unsigned vera_pal_get(char index);
void vera_pal_putn(char index, const unsigned * color, unsigned size);
void vera_pal_getn(char index, unsigned * color, unsigned size);
#pragma compile("vera.c")
#endif
+911
View File
@@ -0,0 +1,911 @@
#include "fixmath.h"
unsigned long lmul16u(unsigned x, unsigned y)
{
__asm
{
lda #0
sta accu + 2
sta accu + 3
ldx #16
L1: lsr x + 1
ror x
bcc W1
clc
lda accu + 2
adc y
sta accu + 2
lda accu + 3
adc y + 1
sta accu + 3
W1:
ror accu + 3
ror accu + 2
ror accu + 1
ror accu
dex
bne L1
}
}
long lmul16s(int x, int y)
{
__asm
{
bit y + 1
bpl W0
sec
lda #0
sbc y
sta y
lda #0
sbc y + 1
sta y + 1
sec
lda #0
sbc x
sta x
lda #0
sbc x + 1
sta x + 1
W0:
ldx #15
lda #0
sta accu + 2
L1: lsr x + 1
ror x
bcc W1
tay
clc
lda accu + 2
adc y
sta accu + 2
tya
adc y + 1
W1:
ror
ror accu + 2
ror accu + 1
ror accu
dex
bne L1
lsr x
bcc W2
tay
sec
lda accu + 2
sbc y
sta accu + 2
tya
sbc y + 1
sec
W2:
ror
ror accu + 2
ror accu + 1
ror accu
sta accu + 3
}
}
inline int lmul12f4s(int x, int y)
{
return (int)(lmul16s(x, y) >> 4);
}
inline int lmul8f8s(int x, int y)
{
return (int)(lmul16s(x, y) >> 8);
}
inline unsigned long lsqr4f12s(int x)
{
if (x < 0) x = -x;
return lmul16u(x, x);
}
int lmul4f12s(int x, int y)
{
__asm
{
sec
lda x
ror
sta accu
lda #0
sta accu + 1
bcc W4
L2:
tay
clc
lda accu + 1
adc y
sta accu + 1
tya
adc y + 1
W4:
ror
ror accu + 1
lsr accu
bcc W4
bne L2
ldx x + 1
stx accu
ldx #7
lsr accu
L1:
bcc W1
tay
clc
lda accu + 1
adc y
sta accu + 1
tya
adc y + 1
W1:
ror
ror accu + 1
ror accu
dex
bne L1
bcc W2
tay
// sec ; we know it is set here
lda accu + 1
sbc y
sta accu + 1
tya
sbc y + 1
W2:
ror
ror accu + 1
ror accu
bit y + 1
bpl W3
tax
sec
lda accu + 1
sbc x
sta accu + 1
txa
sbc x + 1
W3:
lsr
ror accu + 1
ror accu
lsr
ror accu + 1
ror accu
lsr
ror accu + 1
ror accu
lsr
ror accu + 1
ror accu
}
}
unsigned ldiv16u(unsigned long x, unsigned y)
{
__asm
{
lda #0
sta accu
sta accu + 1
ldx #17
L1:
sec
lda x + 2
sbc y
tay
lda x + 3
sbc y + 1
bcc W1
sta x + 3
sty x + 2
W1:
rol accu
rol accu + 1
asl x
rol x + 1
rol x + 2
rol x + 3
dex
beq E1
bcc L1
lda x + 2
sbc y
sta x + 2
lda x + 3
sbc y + 1
sta x + 3
sec
bcs W1
E1:
}
}
int ldiv16s(long x, int y)
{
if (x < 0)
{
if (y < 0)
return ldiv16u(-x, - y);
else
return -ldiv16u(-x, y);
}
else if (y < 0)
return -ldiv16u(x, -y);
else
return ldiv16u(x, y);
}
inline int ldiv12f4s(int x, int y)
{
return (int)(ldiv16s((long)x << 4, y));
}
inline int ldiv8f8s(int x, int y)
{
return (int)(ldiv16s((long)x << 8, y));
}
inline int ldiv4f12s(int x, int y)
{
return (int)(ldiv16s((long)x << 12, y));
}
unsigned lmuldiv16u(unsigned a, unsigned b, unsigned c)
{
__asm
{
lda #0
sta __tmp + 2
sta __tmp + 3
lda a
sec
T1:
ldy #8
L1:
ror
bcc W1
tax
clc
lda __tmp + 2
adc b
sta __tmp + 2
lda __tmp + 3
adc b + 1
sta __tmp + 3
txa
W1:
ror __tmp + 3
ror __tmp + 2
dey
bne L1
ror
bcc T2
sta __tmp + 0
lda a + 1
clc
bcc T1
T2:
sec
L3:
sta __tmp + 1
ldx #8
L2:
rol __tmp + 1
rol __tmp + 2
rol __tmp + 3
bcc W3
lda __tmp + 2
sbc c
tay
lda __tmp + 3
sbc c + 1
sec
bcs W4
W3:
sec
lda __tmp + 2
sbc c
tay
lda __tmp + 3
sbc c + 1
bcc W2
W4:
sta __tmp + 3
sty __tmp + 2
W2:
dex
bne L2
lda __tmp + 1
rol
bcc T3
sta accu + 1
lda __tmp + 0
clc
bcc L3
T3:
sta accu
}
}
int lmuldiv16s(int a, int b, int c)
{
bool sign = false;
if (a < 0)
{
a = -a;
sign = !sign;
}
if (b < 0)
{
b = -b;
sign = !sign;
}
if (c < 0)
{
c = -c;
sign = !sign;
}
__asm
{
lda #0
sta __tmp + 2
sta __tmp + 3
lda a
sec
T1:
ldy #8
L1:
ror
bcc W1
tax
clc
lda __tmp + 2
adc b
sta __tmp + 2
lda __tmp + 3
adc b + 1
sta __tmp + 3
txa
W1:
ror __tmp + 3
ror __tmp + 2
dey
bne L1
ror
bcc T2
sta __tmp + 0
lda a + 1
clc
bcc T1
T2:
sec
L3:
sta __tmp + 1
ldx #8
L2:
rol __tmp + 1
rol __tmp + 2
rol __tmp + 3
bcc W3
lda __tmp + 2
sbc c
tay
lda __tmp + 3
sbc c + 1
sec
bcs W4
W3:
sec
lda __tmp + 2
sbc c
tay
lda __tmp + 3
sbc c + 1
bcc W2
W4:
sta __tmp + 3
sty __tmp + 2
W2:
dex
bne L2
lda __tmp + 1
rol
bcc T3
sta accu + 1
lda __tmp + 0
clc
bcc L3
T3:
sta accu
lda sign
beq E1
sec
lda #0
sbc accu
sta accu
lda #0
sbc accu + 1
sta accu + 1
E1:
}
}
unsigned lmuldiv16by8(unsigned a, char b, char c)
{
__asm {
lda #0
sta accu + 0
sta accu + 1
sta accu + 2
sta accu + 3
lda b
beq z1
lda c
l1:
asl
bcs e1
cmp b
bcs e2
asl a + 0
rol a + 1
jmp l1
e2:
clc
e1:
ror
sta c
ldx #16
l2:
lda b
sec
sbc c
bcc w1
sta b
clc
lda accu + 2
adc a
sta accu + 2
lda accu + 3
adc a + 1
sta accu + 3
bcc * + 8
inc accu + 0
bne * + 4
inc accu + 1
w1:
asl accu + 2
rol accu + 3
rol accu + 0
rol accu + 1
asl b
bcc w2
lda b
sbc c
sta b
clc
lda accu + 2
adc a
sta accu + 2
lda accu + 3
adc a + 1
sta accu + 3
bcc * + 8
inc accu + 0
bne * + 4
inc accu + 1
w2:
dex
bne l2
z1:
}
}
unsigned lmuldiv8by8(char a, char b, char c)
{
__asm {
ldy #0
sty accu + 0
sty accu + 1
sty accu + 2
lda a
beq z1
lda c
beq z1
ldx #8
lda b
beq z1
cmp c
bcc w0
l1:
lsr
ror accu + 1
inx
cmp c
bcs l1
bcc wa
l2:
asl accu + 2
rol accu + 0
wa:
rol accu + 1
w0:
rol
bcc w2
sbc c
bcc w3
w2:
tay
sec
sbc c
bcc w1
w3:
tay
clc
lda accu + 2
adc a
sta accu + 2
bcc w1
inc accu + 0
bne w1
inc accu + 1
w1:
tya
dex
bne l2
z1:
}
}
int lmuldiv16sby8(int a, char b, char c)
{
if (a < 0)
return -(int)lmuldiv16by8(-a, b, c);
else
return lmuldiv16by8(a, b, c);
}
unsigned usqrt(unsigned n)
{
unsigned p, q, r, h;
p = 0;
r = n;
#assign q 0x4000
#repeat
{
h = p | q;
p >>= 1;
if (r >= h)
{
p |= q;
r -= h;
}
}
#assign q q >> 2
#until q == 0
#undef q
return p;
}
unsigned long lmul16f16(unsigned long x, unsigned long y)
{
unsigned long hh = lmul16u(x >> 16, y >> 16);
unsigned long lh = lmul16u(x, y >> 16);
unsigned long hl = lmul16u(x >> 16, y);
unsigned long ll = lmul16u(x, y);
if (ll & 0x8000)
lh++;
ll >>= 16;
ll |= hh << 16;
ll += lh;
ll += hl;
return ll;
}
#if 1
long lmul16f16s(long x, long y)
{
__asm
{
lda #0
// fractional
sta __tmp + 0
sta __tmp + 1
// result
sta __accu + 0
sta __accu + 1
sta __accu + 2
sta __accu + 3
lda x + 0
ora x + 1
ora y + 0
ora y + 1
bne w0b
l2:
lsr x + 2
bcc ws1
clc
lda y + 2
adc __accu + 2
sta __accu + 2
lda y + 3
adc __accu + 3
sta __accu + 3
ws1:
lsr x + 3
bcc ws2
clc
lda y + 2
adc __accu + 3
sta __accu + 3
ws2:
asl y + 2
rol y + 3
lda x + 2
ora x + 3
bne l2
rts
w0b:
lda y + 3
and #$80
beq w0
lda #$ff
w0:
// overflow
sta __tmp + 2
sta __tmp + 3
lda x + 3
bpl w0a
sec
lda #0
sbc y + 0
sta __accu + 2
lda #0
sbc y + 1
sta __accu + 3
w0a:
ldx #8
l1:
lsr x + 0
bcc w1
clc
lda y + 0
adc __tmp + 0
sta __tmp + 0
lda y + 1
adc __tmp + 1
sta __tmp + 1
lda y + 2
adc __accu + 0
sta __accu + 0
lda y + 3
adc __accu + 1
sta __accu + 1
lda __tmp + 2
adc __accu + 2
sta __accu + 2
lda __tmp + 3
adc __accu + 3
sta __accu + 3
w1:
lsr x + 1
bcc w2
clc
lda y + 0
adc __tmp + 1
sta __tmp + 1
lda y + 1
adc __accu + 0
sta __accu + 0
lda y + 2
adc __accu + 1
sta __accu + 1
lda y + 3
adc __accu + 2
sta __accu + 2
lda __tmp + 2
adc __accu + 3
sta __accu + 3
w2:
lsr x + 2
bcc w3
clc
lda y + 0
adc __accu + 0
sta __accu + 0
lda y + 1
adc __accu + 1
sta __accu + 1
lda y + 2
adc __accu + 2
sta __accu + 2
lda y + 3
adc __accu + 3
sta __accu + 3
w3:
lsr x + 3
bcc w4
clc
lda y + 0
adc __accu + 1
sta __accu + 1
lda y + 1
adc __accu + 2
sta __accu + 2
lda y + 2
adc __accu + 3
sta __accu + 3
w4:
asl y + 0
rol y + 1
rol y + 2
rol y + 3
rol __tmp + 2
rol __tmp + 3
dex
beq w5
jmp l1
w5:
}
}
#else
__native long lmul16f16s(long x, long y)
{
unsigned lox = x;
int hix = x >> 16;
unsigned loy = y;
int hiy = y >> 16;
long r = (long)(hix * hiy) << 16;
if (lox)
{
r += lmul16u(lox, hiy);
if (hiy < 0)
r -= (unsigned long)lox << 16;
}
if (loy)
{
r += lmul16u(loy, hix);
if (hix < 0)
r -= (unsigned long)loy << 16;
}
if (lox && loy)
{
r += lmul16u(lox, loy) >> 16;
}
return r;
}
#endif
__native unsigned long ldiv16f16(unsigned long x, unsigned long y)
{
unsigned long k = x >> 16, d = 0;
x <<= 16;
for(char i=0; i<32; i++)
{
d <<= 1;
k <<= 1;
k |= (x >> 31);
x <<= 1;
if (k >= y)
{
k -= y;
d |= 1;
}
}
return d;
}
__native long ldiv16f16s(long x, long y)
{
bool sign = false;
if (x < 0)
{
x = -x;
sign = true;
}
if (y < 0)
{
y = -y;
sign = !sign;
}
x = ldiv16f16(x, y);
if (sign)
return -x;
else
return x;
}
+64
View File
@@ -0,0 +1,64 @@
#ifndef FIXMATH_H
#define FIXMATH_H
// Multiply two unsigned 16bit numbers and return a 32bit result
__native unsigned long lmul16u(unsigned x, unsigned y);
// Multiply two signed 16bit numbers and return a signed 32bit result
__native long lmul16s(int x, int y);
// Multiply two 12.4 fixpoint numbers and return a 12.4 fixpoint result
inline int lmul12f4s(int x, int y);
// Multiply two 8.8 fixpoint numbers and return an 8.8 fixpoint result
inline int lmul8f8s(int x, int y);
// Multiply two 4.12 fixpoint numbers and return a 12.4 fixpoint result
__native int lmul4f12s(int x, int y);
// Square of a 4.12 sigend fixpoint number and return an 8.24 fixpoint result
inline unsigned long lsqr4f12s(int x);
// Divide a 32bit unsigned number by a 16bit number and return a 16bit number
__native unsigned ldiv16u(unsigned long x, unsigned y);
// Divide a signed 32bit number by a signed 16bit number and return a signed 16bit number
__native int ldiv16s(long x, int y);
// Divide a 12.4 fixed point number by a 12.4 fixpoint number
inline int ldiv12f4s(int x, int y);
// Divide a 8.8 fixed point number by an 8.8 fixpoint number
inline int ldiv8f8s(int x, int y);
// Divide a 4.12 fixed point number by a 4.12 fixpoint number
inline int ldiv4f12s(int x, int y);
// Multiply two unsigned 16bit numbers and divide the result by another 16bit number a * b / c
__native unsigned lmuldiv16u(unsigned a, unsigned b, unsigned c);
// Multiply two signed 16bit numbers and divide the result by another signed 16bit number a * b / c
__native int lmuldiv16s(int a, int b, int c);
__native unsigned lmuldiv16by8(unsigned a, char b, char c);
inline int lmuldiv16sby8(int a, char b, char c);
__native unsigned lmuldiv8by8(char a, char b, char c);
__native unsigned usqrt(unsigned n);
__native unsigned long lmul16f16(unsigned long x, unsigned long y);
__native long lmul16f16s(long x, long y);
__native unsigned long ldiv16f16(unsigned long x, unsigned long y);
__native long ldiv16f16s(long x, long y);
#pragma compile("fixmath.c")
#endif
File diff suppressed because it is too large Load Diff
+172
View File
@@ -0,0 +1,172 @@
#ifndef BITMAP_H
#define BITMAP_H
#include <c64/types.h>
struct Bitmap
{
char * data, * rdata;
char cwidth;
char cheight;
unsigned width;
};
struct ClipRect
{
int left, top, right, bottom;
};
#define BLIT_OP 0x03
#define BLIT_AND 0x01
#define BLIT_ORA 0x02
#define BLIT_EOR 0x03
#define BLIT_IMM 0x04
#define BLIT_SRC 0x08
#define BLIT_DST 0x10
#define BLIT_PATTERN 0x20
#define BLIT_INVERT 0x40
enum BlitOp
{
BLTOP_SET = BLIT_IMM | BLIT_INVERT,
BLTOP_RESET = BLIT_IMM,
BLTOP_NOT = BLIT_DST | BLIT_IMM | BLIT_INVERT | BLIT_EOR,
BLTOP_XOR = BLIT_SRC | BLIT_DST | BLIT_EOR,
BLTOP_OR = BLIT_SRC | BLIT_DST | BLIT_ORA,
BLTOP_AND = BLIT_SRC | BLIT_DST | BLIT_AND,
BLTOP_AND_NOT = BLIT_SRC | BLIT_DST | BLIT_INVERT | BLIT_AND,
BLTOP_COPY = BLIT_SRC,
BLTOP_NCOPY = BLIT_SRC | BLIT_INVERT,
BLTOP_PATTERN = BLIT_PATTERN,
BLTOP_PATTERN_AND_SRC = BLIT_SRC | BLIT_PATTERN | BLIT_AND
};
enum LineOp
{
LINOP_SET,
LINOP_OR,
LINOP_AND,
LINOP_XOR
};
extern char NineShadesOfGrey[9][8];
// Fast unsigned integer square root
unsigned bm_usqrt(unsigned n);
// Initialize a bitmap structure, size is given in char cells (8x8 pixel)
void bm_init(Bitmap * bm, char * data, char cw, char ch);
// Initialize a bitmap structure with allocated memory, size is given in char cells (8x8 pixel)
void bm_alloc(Bitmap * bm, char cw, char ch);
// Free the memory of a bitmap
void bm_free(Bitmap * bm);
// Fill a bitmap with the data byte
void bm_fill(const Bitmap * bm, char data);
void bm_scan_fill(int left, int right, char * lp, int x0, int x1, char pat);
// Fill a circle with center x/y and radius r and the 8x8 pattern pat.
void bm_circle_fill(const Bitmap * bm, const ClipRect * clip, int x, int y, char r, const char * pat);
// Fill a trapezoid with horizontal top and bottom, top left is in x0, top right in x1
// dx0 and dx1 are the horizontal delta for each line. Coordinates are in 16.16 fixed point
// numbers. y0 and y1 are vertical coordinates in pixel.
void bm_trapezoid_fill(const Bitmap * bm, const ClipRect * clip, long x0, long x1, long dx0, long dx1, int y0, int y1, const char * pat);
// Fill a triangle with a pattern, coordinate pairs x0/y0, x1/y1 and x2/y2 are in pixel
void bm_triangle_fill(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, int x2, int y2, const char * pat);
// Fill a quad with a pattern, coordinate pairs are in pixel
void bm_quad_fill(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, const char * pat);
// Fill a convex polygon with a pattern, coordinate pairs x[]/y[] are in pixel
void bm_polygon_fill(const Bitmap * bm, const ClipRect * clip, int * x, int * y, char num, const char * pat);
// Fill an arbitrary polygon with a pattern, coordinate pairs x[]/y[] are in pixel, maximum size is
// sixteen vertices
void bm_polygon_nc_fill(const Bitmap * bm, const ClipRect * clip, int * x, int * y, char num, const char * pat);
// Set a single pixel
inline void bm_set(const Bitmap * bm, int x, int y);
// Clear a single pixel
inline void bm_clr(const Bitmap * bm, int x, int y);
// Get the state of a single pixel
inline bool bm_get(const Bitmap * bm, int x, int y);
// Set or clear a single pixel
inline void bm_put(const Bitmap * bm, int x, int y, bool c);
// Draw an unclipped line using an eight bit pattern
void bmu_line(const Bitmap * bm, int x0, int y0, int x1, int y1, char pattern, LineOp op);
// Draw a clipped line using an eight bit pattern
void bm_line(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, char pattern, LineOp op);
// Unclipped bit blit
void bmu_bitblit(const Bitmap * dbm, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h, const char * pattern, BlitOp op);
// Unclipped rectangle fill
inline void bmu_rect_fill(const Bitmap * dbm, int dx, int dy, int w, int h);
// Unclipped rectangle clear
inline void bmu_rect_clear(const Bitmap * dbm, int dx, int dy, int w, int h);
// Unclipped rectangle pattern fill
inline void bmu_rect_pattern(const Bitmap * dbm, int dx, int dy, int w, int h, const char * pattern);
// Unclipped rectangle copy
inline void bmu_rect_copy(const Bitmap * dbm, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h);
// Clipped bit blit
void bm_bitblit(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h, const char * pattern, BlitOp op);
// Clipped rectangle fill
inline void bm_rect_fill(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h);
// Clipped rectangle clear
inline void bm_rect_clear(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h);
// Clipped rectangle pattern fill
inline void bm_rect_pattern(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h, const char * pattern);
// Clipped rectangle copy
inline void bm_rect_copy(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h);
// Unclipped text rendering
int bmu_text(const Bitmap * bm, char lx, const char * str, char len);
// Calculate size of a char range
int bmu_text_size(const char * str, char len);
// Unclipped text output to an arbitrary location using a bit blit
int bmu_put_chars(const Bitmap * bm, int x, int y, const char * str, char len, BlitOp op);
// Clipped text output to an arbitrary location using a bit blit
int bm_put_chars(const Bitmap * bm, const ClipRect * clip, int x, int y, const char * str, char len, BlitOp op);
// Clipped text output of a zero terminated string to an arbitrary location using a bit blit
inline int bm_put_string(const Bitmap * bm, const ClipRect * clip, int x, int y, const char * str, BlitOp op);
// Linear transformation of a source bitmap rectangle to a destination rectangle
int bm_transform(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h, const Bitmap * sbm, int sx, int sy, int dxx, int dxy, int dyx, int dyy);
#pragma compile("bitmap.c")
#endif
+921
View File
@@ -0,0 +1,921 @@
#include "mcbitmap.h"
#include <c64/asm6502.h>
static char andmask[8] = {0x3f, 0x3f, 0xcf, 0xcf, 0xf3, 0xf3, 0xfc, 0xfc};
static char ormask[8] = {0xc0, 0xc0, 0x30, 0x30, 0x0c, 0x0c, 0x03, 0x03};
static char cbytes[4] = {0x00, 0x55, 0xaa, 0xff};
char MixedColors[4][4][8] = {
{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44},
{0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88},
{0x33, 0xcc, 0x33, 0xcc, 0x33, 0xcc, 0x33, 0xcc},
},
{
{0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11},
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55},
{0x66, 0x99, 0x66, 0x99, 0x66, 0x99, 0x66, 0x99},
{0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd},
},
{
{0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22},
{0x99, 0x66, 0x99, 0x66, 0x99, 0x66, 0x99, 0x66},
{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
{0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee},
},
{
{0xcc, 0x33, 0xcc, 0x33, 0xcc, 0x33, 0xcc, 0x33},
{0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77},
{0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
},
};
void bmmc_put(const Bitmap * bm, int x, int y, char c)
{
char * dp = bm->data + bm->cwidth * (y & ~7) + ((x & ~7) | (y & 7));
char pat = cbytes[c & 3];
*dp = ((*dp ^ pat) & andmask[x & 7]) ^ pat;
}
char bmmc_get(const Bitmap * bm, int x, int y)
{
char * dp = bm->data + bm->cwidth * (y & ~7) + (x & ~7) + (y & 7);
return (*dp >> (6 - (x & 6))) & 3;
}
void bmmcu_circle(const Bitmap * bm, int x, int y, char r, char color)
{
char * lpt = bm->data + bm->cwidth * (y & ~7) + (y & 7);
char * lpb = lpt;
int stride = 8 * bm->cwidth - 8;
char pat = ~cbytes[color & 3];
char rx = r, ry = 0;
int d = r / 2;
char * dp;
while (rx > 0)
{
dp = lpt + ((x + rx) & ~7);
*dp = ((*dp ^ pat) | ormask[(x + rx) & 7]) ^ pat;
dp = lpt + ((x - rx) & ~7);
*dp = ((*dp ^ pat) | ormask[(x - rx) & 7]) ^ pat;
dp = lpb + ((x + rx) & ~7);
*dp = ((*dp ^ pat) | ormask[(x + rx) & 7]) ^ pat;
dp = lpb + ((x - rx) & ~7);
*dp = ((*dp ^ pat) | ormask[(x - rx) & 7]) ^ pat;
if (d >= 0)
{
ry++;
d -= ry;
lpb ++;
if (!((int)lpb & 7))
lpb += stride;
if (!((int)lpt & 7))
lpt -= stride;
lpt--;
}
if (d < 0)
{
rx--;
d += rx;
}
}
dp = lpt + (x & ~7);
*dp = ((*dp ^ pat) | ormask[x & 7]) ^ pat;
dp = lpb + (x & ~7);
*dp = ((*dp ^ pat) | ormask[x & 7]) ^ pat;
}
void bmmc_circle2(const Bitmap * bm, const ClipRect * clip, int x, int y, char r, char color)
{
char * lpt = bm->data + bm->cwidth * (y & ~7) + (y & 7);
char * lpb = lpt;
int stride = 8 * bm->cwidth - 8;
char pat = ~cbytes[color & 3];
char rx = r, ry = 0;
int d = r / 2;
char * dp;
y -= clip->top;
unsigned h = clip->bottom - clip->top;
unsigned y0 = y, y1 = y;
while (rx > 0)
{
int x0 = x - rx, x1 = x + rx;
bool c0 = x0 >= clip->left && x0 < clip->right;
bool c1 = x1 >= clip->left && x1 < clip->right;
if ((unsigned)y0 < h)
{
if (c0)
{
dp = lpt + (x0 & ~7);
*dp = ((*dp ^ pat) | ormask[x0 & 7]) ^ pat;
}
if (c1)
{
dp = lpt + (x1 & ~7);
*dp = ((*dp ^ pat) | ormask[x1 & 7]) ^ pat;
}
}
if ((unsigned)y1 < h)
{
if (c0)
{
dp = lpb + (x0 & ~7);
*dp = ((*dp ^ pat) | ormask[x0 & 7]) ^ pat;
}
if (c1)
{
dp = lpb + (x1 & ~7);
*dp = ((*dp ^ pat) | ormask[x1 & 7]) ^ pat;
}
}
if (d >= 0)
{
ry++; y0--; y1++;
d -= ry;
lpb ++;
if (!((int)lpb & 7))
lpb += stride;
if (!((int)lpt & 7))
lpt -= stride;
lpt--;
}
if (d < 0)
{
rx--;
d += rx;
}
}
if (x >= clip->left && x < clip->right)
{
if ((unsigned)y0 < h)
{
dp = lpt + (x & ~7);
*dp = ((*dp ^ pat) | ormask[x & 7]) ^ pat;
}
if ((unsigned)y1 < h)
{
dp = lpb + (x & ~7);
*dp = ((*dp ^ pat) | ormask[x & 7]) ^ pat;
}
}
}
void bmmc_circle(const Bitmap * bm, const ClipRect * clip, int x, int y, char r, char color)
{
if (x - r >= clip->left && x + r < clip->right && y - r >= clip->top && y + r < clip->bottom)
bmmcu_circle(bm, x, y, r, color);
else if (x - r < clip->right && x + r >= clip->left && y - r < clip->bottom && y + r >= clip->top)
bmmc_circle2(bm, clip, x, y, r, color);
}
void bmmc_scan_fill(int left, int right, char * lp, int x0, int x1, char pat)
{
bm_scan_fill(left, right, lp, x0 & ~1, (x1 + 1) & ~1, pat);
}
void bmmc_circle_fill(const Bitmap * bm, const ClipRect * clip, int x, int y, char r, const char * pattern)
{
int y0 = y - r, y1 = y + r + 1;
if (y0 < clip->top)
y0 = clip->top;
if (y1 > clip->bottom)
y1 = clip->bottom;
const char * pat = pattern;
char * lp = bm->data + bm->cwidth * (y0 & ~7) + (y0 & 7);
int stride = 8 * bm->cwidth - 8;
unsigned rr = r * r + r;
unsigned d = rr - (y0 - y) * (y0 - y);
int tt = 2 * (y0 - y) + 1;
for(char iy=y0; iy<(char)y1; iy++)
{
int t = bm_usqrt(d);
bmmc_scan_fill(clip->left, clip->right, lp, x - t, x + t + 1, pat[iy & 7]);
lp ++;
if (!((int)lp & 7))
lp += stride;
d -= tt;
tt += 2;
}
}
void bmmc_trapezoid_fill(const Bitmap * bm, const ClipRect * clip, long x0, long x1, long dx0, long dx1, int y0, int y1, const char * pattern)
{
if (y1 <= clip->top || y0 >= clip->bottom)
return;
long tx0 = x0, tx1 = x1;
if (y1 > clip->bottom)
y1 = clip->bottom;
if (y0 < clip->top)
{
tx0 += (clip->top - y0) * dx0;
tx1 += (clip->top - y0) * dx1;
y0 = clip->top;
}
const char * pat = pattern;
char * lp = bm->data + bm->cwidth * (y0 & ~7) + (y0 & 7);
int stride = 8 * bm->cwidth - 8;
for(char iy=y0; iy<(char)y1; iy++)
{
bmmc_scan_fill(clip->left, clip->right, lp, tx0 >> 16, tx1 >> 16, pat[iy & 7]);
tx0 += dx0;
tx1 += dx1;
lp ++;
if (!((int)lp & 7))
lp += stride;
}
}
void bmmc_triangle_fill(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, int x2, int y2, const char * pat)
{
int t;
if (y1 < y0 && y1 < y2)
{
t = y0; y0 = y1; y1 = t;
t = x0; x0 = x1; x1 = t;
}
else if (y2 < y0)
{
t = y0; y0 = y2; y2 = t;
t = x0; x0 = x2; x2 = t;
}
if (y2 < y1)
{
t = y1; y1 = y2; y2 = t;
t = x1; x1 = x2; x2 = t;
}
if (y0 < y2)
{
long dx1, lx1;
long dx2 = ((long)(x2 - x0) << 16) / (y2 - y0);
long lx2 = (long)x0 << 16;
if (y1 > y0)
{
dx1 = ((long)(x1 - x0) << 16) / (y1 - y0);
if (dx1 < dx2)
bmmc_trapezoid_fill(bm, clip, lx2, lx2, dx1, dx2, y0, y1, pat);
else
bmmc_trapezoid_fill(bm, clip, lx2, lx2, dx2, dx1, y0, y1, pat);
if (y2 == y1)
return;
lx2 += dx2 * (y1 - y0);
}
dx1 = ((long)(x2 - x1) << 16) / (y2 - y1);
lx1 = (long)x1 << 16;
if (lx1 < lx2)
bmmc_trapezoid_fill(bm, clip, lx1, lx2, dx1, dx2, y1, y2, pat);
else
bmmc_trapezoid_fill(bm, clip, lx2, lx1, dx2, dx1, y1, y2, pat);
}
}
void bmmc_quad_fill(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, const char * pat)
{
bmmc_triangle_fill(bm, clip, x0, y0, x1, y1, x2, y2, pat);
bmmc_triangle_fill(bm, clip, x0, y0, x2, y2, x3, y3, pat);
}
void bmmc_polygon_fill(const Bitmap * bm, const ClipRect * clip, int * px, int * py, char num, const char * pat)
{
char mi = 0;
int my = py[0];
for(char i=1; i<num; i++)
{
if (py[i] < my)
{
my = py[i];
mi = i;
}
}
char li = mi, ri = mi;
long lx, rx;
do
{
lx = (long)px[li] << 16;
if (li == 0)
li = num;
li--;
} while(py[li] == my);
do
{
rx = (long)px[ri] << 16;
ri++;
if (ri == num)
ri = 0;
}
while (py[ri] == my);
int ty = py[li] < py[ri] ? py[li] : py[ri];
while (ty > my)
{
long dlx = (((long)px[li] << 16) - lx) / (py[li] - my);
long drx = (((long)px[ri] << 16) - rx) / (py[ri] - my);
if (lx < rx || lx == rx && dlx < drx)
bmmc_trapezoid_fill(bm, clip, lx, rx, dlx, drx, my, ty, pat);
else
bmmc_trapezoid_fill(bm, clip, rx, lx, drx, dlx, my, ty, pat);
lx += (ty - my) * dlx;
rx += (ty - my) * drx;
my = ty;
while (py[li] == my)
{
lx = (long)px[li] << 16;
if (li == 0)
li = num;
li--;
}
while (py[ri] == my)
{
rx = (long)px[ri] << 16;
ri++;
if (ri == num)
ri = 0;
}
ty = py[li] < py[ri] ? py[li] : py[ri];
}
}
struct Edge
{
char minY, maxY;
long px, dx;
Edge * next;
};
void bmmc_polygon_nc_fill(const Bitmap * bm, const ClipRect * clip, int * px, int * py, char num, const char * pattern)
{
Edge * first = nullptr, * active = nullptr;
Edge * e = (Edge *)BLIT_CODE;
char n = num;
if (n > 16)
n = 16;
int top = clip->top, bottom = clip->bottom;
for(char i=0; i<n; i++)
{
char j = i + 1, k = i;
if (j >= n)
j = 0;
if (py[i] != py[j])
{
if (py[i] > py[j])
{
k = j; j = i;
}
int minY = py[k], maxY = py[j];
if (minY < bottom && maxY > top)
{
e->px = ((long)px[k] << 16) + 0x8000;
e->dx = (((long)px[j] << 16) - e->px) / (maxY - minY);
if (minY < top)
{
e->px += e->dx * (top - minY);
minY = top;
}
if (maxY > bottom)
maxY = bottom;
e->minY = minY; e->maxY = maxY;
Edge * pp = nullptr, * pe = first;
while (pe && minY >= pe->minY)
{
pp = pe;
pe = pe->next;
}
e->next = pe;
if (pp)
pp->next = e;
else
first = e;
e++;
}
}
}
if (first)
{
char y = first->minY;
const char * pat = pattern;
char * lp = bm->data + bm->cwidth * (y & ~7) + (y & 7);
int stride = 8 * bm->cwidth - 8;
while (first || active)
{
while (first && first->minY == y)
{
Edge * next = first->next;
Edge * pp = nullptr, * pe = active;
while (pe && (first->px > pe->px || first->px == pe->px && first->dx > pe->dx))
{
pp = pe;
pe = pe->next;
}
first->next = pe;
if (pp)
pp->next = first;
else
active = first;
first = next;
}
Edge * e0 = active;
while (e0)
{
Edge * e1 = e0->next;
bmmc_scan_fill(clip->left, clip->right, lp, e0->px >> 16, e1->px >> 16, pat[y & 7]);
e0 = e1->next;
}
lp ++;
if (!((int)lp & 7))
lp += stride;
y++;
// remove final edges
Edge * pp = nullptr, * pe = active;
while (pe)
{
if (pe->maxY == y)
{
if (pp)
pp->next = pe->next;
else
active = pe->next;
}
else
{
pe->px += pe->dx;
pp = pe;
}
pe = pe->next;
}
}
}
}
#define REG_SP 0x03
#define REG_DP 0x05
#define REG_PAT 0x07
#define REG_S0 0x08
#define REG_S1 0x09
#define REG_D0 0x0a
#define REG_D1 0x0b
static void mbuildline(char ly, char lx, int dx, int dy, int stride, bool left, bool up, char color)
{
char ip = 0;
// ylow
ip += asm_im(BLIT_CODE + ip, ASM_LDY, ly);
ip += asm_im(BLIT_CODE + ip, ASM_LDX, lx);
// set pixel
ip += asm_iy(BLIT_CODE + ip, ASM_LDA, REG_SP);
ip += asm_im(BLIT_CODE + ip, ASM_EOR, color);
ip += asm_zp(BLIT_CODE + ip, ASM_ORA, REG_D0);
ip += asm_im(BLIT_CODE + ip, ASM_EOR, color);
ip += asm_iy(BLIT_CODE + ip, ASM_STA, REG_SP);
// m >= 0
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_DP + 1);
ip += asm_rl(BLIT_CODE + ip, ASM_BMI, 5 + 15 + 13);
ip += asm_np(BLIT_CODE + ip, up ? ASM_DEY : ASM_INY);
ip += asm_im(BLIT_CODE + ip, ASM_CPY, up ? 0xff : 0x08);
ip += asm_rl(BLIT_CODE + ip, ASM_BNE, 15);
ip += asm_np(BLIT_CODE + ip, ASM_CLC);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_SP);
ip += asm_im(BLIT_CODE + ip, ASM_ADC, stride & 0xff);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_SP);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_SP + 1);
ip += asm_im(BLIT_CODE + ip, ASM_ADC, stride >> 8);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_SP + 1);
ip += asm_im(BLIT_CODE + ip, ASM_LDY, up ? 0x07 : 0x00);
ip += asm_np(BLIT_CODE + ip, ASM_SEC);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_DP);
ip += asm_im(BLIT_CODE + ip, ASM_SBC, dx & 0xff);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_DP);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_DP + 1);
ip += asm_im(BLIT_CODE + ip, ASM_SBC, dx >> 8);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_DP + 1);
// m < 0
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_DP + 1);
ip += asm_rl(BLIT_CODE + ip, ASM_BPL, 4 + 15 + 13);
ip += asm_zp(BLIT_CODE + ip, left ? ASM_ASL : ASM_LSR, REG_D0);
ip += asm_zp(BLIT_CODE + ip, left ? ASM_ROL : ASM_ROR, REG_D0);
ip += asm_rl(BLIT_CODE + ip, ASM_BCC, 15);
ip += asm_zp(BLIT_CODE + ip, left ? ASM_ROL : ASM_ROR, REG_D0);
ip += asm_np(BLIT_CODE + ip, ASM_CLC);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_SP);
ip += asm_im(BLIT_CODE + ip, ASM_ADC, left ? 0xf8 : 0x08);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_SP);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_SP + 1);
ip += asm_im(BLIT_CODE + ip, ASM_ADC, left ? 0xff : 0x00);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_SP + 1);
ip += asm_np(BLIT_CODE + ip, ASM_CLC);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_DP);
ip += asm_im(BLIT_CODE + ip, ASM_ADC, dy & 0xff);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_DP);
ip += asm_zp(BLIT_CODE + ip, ASM_LDA, REG_DP + 1);
ip += asm_im(BLIT_CODE + ip, ASM_ADC, dy >> 8);
ip += asm_zp(BLIT_CODE + ip, ASM_STA, REG_DP + 1);
// l --
ip += asm_np(BLIT_CODE + ip, ASM_DEX);
ip += asm_rl(BLIT_CODE + ip, ASM_BNE, 2 - ip);
ip += asm_zp(BLIT_CODE + ip, ASM_DEC, REG_D1);
ip += asm_rl(BLIT_CODE + ip, ASM_BPL, 2 - ip);
ip += asm_np(BLIT_CODE + ip, ASM_RTS);
}
#pragma native(mbuildline)
static inline void mcallline(byte * dst, byte bit, int m, char lh)
{
__asm
{
lda dst
sta REG_SP
lda dst + 1
sta REG_SP + 1
lda m
sta REG_DP
lda m + 1
sta REG_DP + 1
lda lh
sta REG_D1
lda bit
sta REG_D0
jsr BLIT_CODE
}
}
void bmmcu_line(const Bitmap * bm, int x0, int y0, int x1, int y1, char color)
{
x0 >>= 1;
x1 >>= 1;
int dx = x1 - x0, dy = y1 - y0;
byte quad = 0;
if (dx < 0)
{
quad = 1;
dx = -dx;
}
if (dy < 0)
{
quad |= 2;
dy = -dy;
}
int l;
if (dx > dy)
l = dx;
else
l = dy;
int m = dy - dx;
dx *= 2;
dy *= 2;
char * dp = bm->data + bm->cwidth * (y0 & ~7) + 2 * (x0 & ~3);
char bit = ormask[2 * (x0 & 3)];
char ry = y0 & 7;
int stride = 8 * bm->cwidth;
mbuildline(ry, (l + 1) & 0xff, dx, dy, (quad & 2) ? -stride : stride, quad & 1, quad & 2, ~cbytes[color]);
mcallline(dp, bit, m, l >> 8);
}
static int mmuldiv(int x, int mul, int div)
{
return (int)((long)x * mul / div);
}
void bmmc_line(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, char color)
{
int dx = x1 - x0, dy = y1 - y0;
if (x0 < x1)
{
if (x1 < clip->left || x0 >= clip->right)
return;
if (x0 < clip->left)
{
y0 += mmuldiv(clip->left - x0, dy, dx);
x0 = clip->left;
}
if (x1 >= clip->right)
{
y1 -= mmuldiv(x1 + 1 - clip->right, dy, dx);
x1 = clip->right - 1;
}
}
else if (x1 < x0)
{
if (x0 < clip->left || x1 >= clip->right)
return;
if (x1 < clip->left)
{
y1 += mmuldiv(clip->left - x1, dy, dx);
x1 = clip->left;
}
if (x0 >= clip->right)
{
y0 -= mmuldiv(x0 + 1- clip->right, dy, dx);
x0 = clip->right - 1;
}
}
else
{
if (x0 < clip->left || x0 >= clip->right)
return;
}
if (y0 < y1)
{
if (y1 < clip->top || y0 >= clip->bottom)
return;
if (y0 < clip->top)
{
x0 += mmuldiv(clip->top - y0, dx, dy);
y0 = clip->top;
}
if (y1 >= clip->bottom)
{
x1 -= mmuldiv(y1 + 1 - clip->bottom, dx, dy);
y1 = clip->bottom - 1;
}
}
else if (y1 < y0)
{
if (y0 < clip->top || y1 >= clip->bottom)
return;
if (y1 < clip->top)
{
x1 += mmuldiv(clip->top - y1, dx, dy);
y1 = clip->top;
}
if (y0 >= clip->bottom)
{
x0 -= mmuldiv(y0 + 1 - clip->bottom, dx, dy);
y0 = clip->bottom - 1;
}
}
else
{
if (y0 < clip->top || y0 >= clip->bottom)
return;
}
bmmcu_line(bm, x0, y0, x1, y1, color);
}
void bmmcu_rect_fill(const Bitmap * dbm, int dx, int dy, int w, int h, char color)
{
int rx = (dx + w + 1) & ~1;
dx &= ~1;
bmu_bitblit(dbm, dx, dy, dbm, dx, dy, rx - dx, h, MixedColors[color][color], BLTOP_PATTERN);
}
void bmmcu_rect_pattern(const Bitmap * dbm, int dx, int dy, int w, int h, const char * pattern)
{
int rx = (dx + w + 1) & ~1;
dx &= ~1;
bmu_bitblit(dbm, dx, dy, dbm, dx, dy, rx - dx, h, pattern, BLTOP_PATTERN);
}
void bmmcu_rect_copy(const Bitmap * dbm, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h)
{
int rx = (dx + w + 1) & ~1;
dx &= ~1;
sx &= ~1;
bmu_bitblit(dbm, dx, dy, sbm, sx, sy, rx - dx, h, nullptr, BLTOP_COPY);
}
void bmmc_rect_fill(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h, char color)
{
int rx = (dx + w + 1) & ~1;
dx &= ~1;
bm_bitblit(dbm, clip, dx, dy, dbm, dx, dy, rx - dx, h, MixedColors[color][color], BLTOP_PATTERN);
}
void bmmc_rect_pattern(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h, const char * pattern)
{
int rx = (dx + w + 1) & ~1;
dx &= ~1;
bm_bitblit(dbm, clip, dx, dy, dbm, dx, dy, rx - dx, h, pattern, BLTOP_PATTERN);
}
void bmmc_rect_copy(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h)
{
int rx = (dx + w + 1) & ~1;
dx &= ~1;
sx &= ~1;
bm_bitblit(dbm, clip, dx, dy, sbm, sx, sy, rx - dx, h, nullptr, BLTOP_COPY);
}
extern byte BLIT_CODE[16 * 14];
inline void bmmc_putdp(char * dp, char x, char c)
{
dp += 2 * (x & ~3);
*dp = (*dp & andmask[2 * (x & 3)]) | (c & ormask[2 * (x & 3)]);
}
inline char bmmc_getdp(char * dp, char x)
{
dp += 2 * (x & ~3);
return (*dp >> 2 * (3 - (x & 3))) & 3;
}
inline char bmmc_checkdp(char * dp, char x, char c)
{
dp += 2 * (x & ~3);
return ((*dp ^ c) & ormask[2 * (x & 3)]);
}
void bmmc_flood_fill(const Bitmap * bm, const ClipRect * clip, int x, int y, char color)
{
char bx = (char)(x >> 1), by = (char)y;
char sp = 0;
char left = clip->left >> 1, right = clip->right >> 1;
char * dp = bm->data + bm->cwidth * (by & ~7) + (by & 7);
char back = cbytes[bmmc_getdp(dp, bx)];
color = cbytes[color];
if (back == color)
return;
BLIT_CODE[sp++] = bx;
BLIT_CODE[sp++] = by;
while (sp > 0)
{
by = BLIT_CODE[--sp];
bx = BLIT_CODE[--sp];
dp = bm->data + bm->cwidth * (by & ~7) + (by & 7);
if (bmmc_checkdp(dp, bx, back) == 0)
{
bmmc_putdp(dp, bx, color);
char x0 = bx;
while (x0 > left && bmmc_checkdp(dp, x0 - 1, back) == 0)
{
x0--;
bmmc_putdp(dp, x0, color);
}
char x1 = bx;
while (x1 + 1 < right && bmmc_checkdp(dp, x1 + 1, back) == 0)
{
x1++;
bmmc_putdp(dp, x1, color);
}
bool check = false;
if (by > clip->top)
{
dp = bm->data + bm->cwidth * ((by - 1) & ~7) + ((by - 1) & 7);
for(bx=x0; bx<=x1; bx++)
{
if (bmmc_checkdp(dp, bx, back) == 0)
{
if (!check)
{
BLIT_CODE[sp++] = bx;
BLIT_CODE[sp++] = by - 1;
check = true;
}
}
else
check = false;
}
}
check = false;
if (by + 1 < clip->bottom)
{
dp = bm->data + bm->cwidth * ((by + 1) & ~7) + ((by + 1) & 7);
for(bx=x0; bx<=x1; bx++)
{
if (bmmc_checkdp(dp, bx, back) == 0)
{
if (!check)
{
BLIT_CODE[sp++] = bx;
BLIT_CODE[sp++] = by + 1;
check = true;
}
}
else
check = false;
}
}
}
}
}
#pragma native(bmmc_flood_fill)
+76
View File
@@ -0,0 +1,76 @@
#ifndef MCBITMAP_H
#define MCBITMAP_H
#include "bitmap.h"
extern char MixedColors[4][4][8];
// Set a single pixel
void bmmc_put(const Bitmap * bm, int x, int y, char c);
// Get the state of a single pixel
char bmmc_get(const Bitmap * bm, int x, int y);
// Draw an unclipped line using an eight bit pattern
void bmmcu_line(const Bitmap * bm, int x0, int y0, int x1, int y1, char color);
// Draw a clipped line using an eight bit pattern
void bmmc_line(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, char color);
inline void bmmc_scan_fill(int left, int right, char * lp, int x0, int x1, char pat);
void bmmcu_circle(const Bitmap * bm, int x, int y, char r, char color);
void bmmc_circle(const Bitmap * bm, const ClipRect * clip, int x, int y, char r, char color);
// Fill a circle with center x/y and radius r and the 8x8 pattern pat.
void bmmc_circle_fill(const Bitmap * bm, const ClipRect * clip, int x, int y, char r, const char * pat);
// Fill a trapezoid with horizontal top and bottom, top left is in x0, top right in x1
// dx0 and dx1 are the horizontal delta for each line. Coordinates are in 16.16 fixed point
// numbers. y0 and y1 are vertical coordinates in pixel.
void bmmc_trapezoid_fill(const Bitmap * bm, const ClipRect * clip, long x0, long x1, long dx0, long dx1, int y0, int y1, const char * pat);
// Fill a triangle with a pattern, coordinate pairs x0/y0, x1/y1 and x2/y2 are in pixel
void bmmc_triangle_fill(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, int x2, int y2, const char * pat);
// Fill a quad with a pattern, coordinate pairs are in pixel
void bmmc_quad_fill(const Bitmap * bm, const ClipRect * clip, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, const char * pat);
// Fill a convex polygon with a pattern, coordinate pairs x[]/y[] are in pixel
void bmmc_polygon_fill(const Bitmap * bm, const ClipRect * clip, int * x, int * y, char num, const char * pat);
// Fill an arbitrary polygon with a pattern, coordinate pairs x[]/y[] are in pixel, maximum size is
// sixteen vertices
void bmmc_polygon_nc_fill(const Bitmap * bm, const ClipRect * clip, int * x, int * y, char num, const char * pat);
inline void bmmcu_rect_fill(const Bitmap * dbm, int dx, int dy, int w, int h, char color);
// Unclipped rectangle pattern fill
inline void bmmcu_rect_pattern(const Bitmap * dbm, int dx, int dy, int w, int h, const char * pattern);
// Unclipped rectangle copy
inline void bmmcu_rect_copy(const Bitmap * dbm, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h);
// Clipped rectangle fill
inline void bmmc_rect_fill(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h, char color);
// Clipped rectangle pattern fill
inline void bmmc_rect_pattern(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, int w, int h, const char * pattern);
// Clipped rectangle copy
inline void bmmc_rect_copy(const Bitmap * dbm, const ClipRect * clip, int dx, int dy, const Bitmap * sbm, int sx, int sy, int w, int h);
void bmmc_flood_fill(const Bitmap * bm, const ClipRect * clip, int x, int y, char color);
#pragma compile("mcbitmap.c")
#endif
+39
View File
@@ -0,0 +1,39 @@
#include "tinyfont.h"
const char TinyFont[] = {
0x00, 0x04, 0x05, 0x08, 0x0D, 0x12, 0x17, 0x1C, 0x1D, 0x21, 0x25, 0x2A, 0x2D, 0x2E, 0x31, 0x32,
0x35, 0x39, 0x3D, 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, 0x5E, 0x5F, 0x62, 0x65, 0x68,
0x6C, 0x71, 0x76, 0x7A, 0x7E, 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x95, 0x99, 0x9D, 0xA1, 0xA6, 0xAB,
0xAF, 0xB3, 0xB7, 0xBB, 0xBF, 0xC4, 0xC8, 0xCD, 0xD2, 0xD7, 0xDC, 0xE1, 0xE5, 0xE8, 0xEC, 0xF1,
0xF5, 0xF9, 0xFD, 0x01, 0x05, 0x09, 0x0D, 0x10, 0x14, 0x18, 0x19, 0x1B, 0x1F, 0x21, 0x26, 0x2A,
0x2E, 0x32, 0x36, 0x3A, 0x3E, 0x41, 0x45, 0x49, 0x4E, 0x52, 0x56, 0x5A, 0x5E, 0x5F, 0x63, 0x67,
0x10, 0x04, 0x0C, 0x14, 0x14, 0x14, 0x14, 0x04, 0x10, 0x10, 0x14, 0x0C, 0x04, 0x0C, 0x04, 0x0C,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x04, 0x04, 0x0C, 0x0C, 0x0C, 0x10,
0x14, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x10, 0x10, 0x10, 0x14, 0x14, 0x10,
0x10, 0x10, 0x10, 0x10, 0x14, 0x10, 0x14, 0x14, 0x14, 0x14, 0x14, 0x10, 0x0C, 0x10, 0x14, 0x10,
0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x0D, 0x11, 0x11, 0x05, 0x09, 0x11, 0x09, 0x15, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x0D, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x05, 0x11, 0x11, 0x11,
0x00, 0x00, 0x00, 0x00, 0xFA, 0xC0, 0x00, 0xC0, 0x28, 0x7C, 0x28, 0x7C, 0x28, 0x20, 0x54, 0xD6,
0x54, 0x08, 0x04, 0x48, 0x10, 0x24, 0x40, 0x6C, 0x92, 0x92, 0x6C, 0x0A, 0xC0, 0x38, 0x44, 0x82,
0x82, 0x82, 0x82, 0x44, 0x38, 0x10, 0x54, 0x38, 0x54, 0x10, 0x10, 0x38, 0x10, 0x03, 0x10, 0x10,
0x10, 0x02, 0x06, 0x38, 0xC0, 0x7C, 0x82, 0x82, 0x7C, 0x22, 0x42, 0xFE, 0x02, 0x46, 0x8A, 0x92,
0x62, 0x44, 0x82, 0x92, 0x6C, 0xF0, 0x10, 0x3E, 0x10, 0xE4, 0x92, 0x92, 0x8C, 0x7C, 0x92, 0x92,
0x4C, 0x80, 0x8E, 0x90, 0xE0, 0x6C, 0x92, 0x92, 0x6C, 0x64, 0x92, 0x92, 0x7C, 0x28, 0x0B, 0x10,
0x28, 0x44, 0x28, 0x28, 0x28, 0x44, 0x28, 0x10, 0x40, 0x80, 0x9A, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x50, 0x90, 0x50, 0x3E, 0xFE, 0x92, 0x92, 0x6C, 0x7C, 0x82, 0x82, 0x44, 0xFE, 0x82,
0x82, 0x7C, 0xFE, 0x92, 0x92, 0x82, 0xFE, 0x90, 0x90, 0x80, 0x7C, 0x82, 0x92, 0x1C, 0xFE, 0x10,
0x10, 0xFE, 0x82, 0xFE, 0x82, 0x84, 0x82, 0x82, 0xFC, 0xFE, 0x10, 0x28, 0xC6, 0xFE, 0x02, 0x02,
0x02, 0xFE, 0x40, 0x20, 0x40, 0xFE, 0xFE, 0x40, 0x20, 0x10, 0xFE, 0x7C, 0x82, 0x82, 0x7C, 0xFE,
0x90, 0x90, 0x60, 0x7C, 0x82, 0x84, 0x7A, 0xFE, 0x90, 0x90, 0x6E, 0x64, 0x92, 0x92, 0x4C, 0x80,
0x80, 0xFE, 0x80, 0x80, 0xFC, 0x02, 0x02, 0xFC, 0xE0, 0x18, 0x06, 0x18, 0xE0, 0xFE, 0x04, 0x08,
0x04, 0xFE, 0xC6, 0x28, 0x10, 0x28, 0xC6, 0xE0, 0x10, 0x1E, 0x10, 0xE0, 0x86, 0x8A, 0x92, 0xA2,
0xC2, 0xFE, 0x82, 0x82, 0x82, 0xC0, 0x38, 0x06, 0x82, 0x82, 0x82, 0xFE, 0x20, 0x40, 0x80, 0x40,
0x20, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x2A, 0x2A, 0x1E, 0xFE, 0x22, 0x22,
0x1C, 0x1C, 0x22, 0x22, 0x14, 0x1C, 0x22, 0x22, 0xFE, 0x1C, 0x2A, 0x2A, 0x18, 0x20, 0x7E, 0xA0,
0x18, 0x25, 0x25, 0x3E, 0xFE, 0x20, 0x20, 0x1E, 0xBE, 0x01, 0xBE, 0xFE, 0x10, 0x28, 0x46, 0xFC,
0x02, 0x3E, 0x20, 0x1E, 0x20, 0x1E, 0x3E, 0x20, 0x20, 0x1E, 0x1C, 0x22, 0x22, 0x1C, 0x3F, 0x24,
0x24, 0x18, 0x18, 0x24, 0x24, 0x3F, 0x3E, 0x10, 0x20, 0x10, 0x12, 0x2A, 0x2A, 0x04, 0x20, 0x7C,
0x22, 0x3C, 0x02, 0x02, 0x3E, 0x38, 0x04, 0x02, 0x3C, 0x3C, 0x02, 0x1C, 0x02, 0x3C, 0x26, 0x18,
0x0C, 0x32, 0x38, 0x05, 0x05, 0x3E, 0x26, 0x2A, 0x2A, 0x32, 0x10, 0x6C, 0x82, 0x82, 0xFE, 0x82,
0x82, 0x6C, 0x10, 0x10, 0x20, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00
};
+8
View File
@@ -0,0 +1,8 @@
#ifndef TINYFONT_H
#define TINYFONT_H
extern const char TinyFont[];
#pragma compile("tinyfont.c")
#endif
File diff suppressed because it is too large Load Diff
+294
View File
@@ -0,0 +1,294 @@
#ifndef VECTOR3D_H
#define VECTOR3D_H
struct Vector2
{
float v[2];
};
inline void vec2_set(Vector2 * vd, float x, float y);
void vec2_sum(Vector2 * vd, const Vector2 * v1, const Vector2 * v2);
void vec2_diff(Vector2 * vd, const Vector2 * v1, const Vector2 * v2);
void vec2_add(Vector2 * vd, const Vector2 * vs);
void vec2_sub(Vector2 * vd, const Vector2 * vs);
void vec2_madd(Vector2 * vd, float s, const Vector2 * vs);
void vec2_scale(Vector2 * vd, float s);
void vec2_lincomb(Vector2 * vd, const Vector2 * vb, float x, const Vector2 * vx);
void vec2_lincomb2(Vector2 * vd, const Vector2 * vb, float x, const Vector2 * vx, float y, const Vector2 * vy);
void vec2_lerp(Vector2 * vd, const Vector2 * v1, const Vector2 * v2, float t);
bool vec2_is_zero(const Vector2 * v);
float vec2_vmul(const Vector2 * v1, const Vector2 * v2);
void vec2_norm(Vector2 * v);
float vec2_length(const Vector2 * v);
float vec2_qlength(const Vector2 * v);
float vec2_distance(const Vector2 * v1, const Vector2 * v2);
float vec2_qdistance(const Vector2 * v1, const Vector2 * v2);
struct Matrix2
{
float m[4];
};
void mat2_ident(Matrix2 * md);
void mat2_add(Matrix2 * md, const Matrix2 * ms);
void mat2_scale(Matrix2 * md, float s);
void mat2_mmul(Matrix2 * md, const Matrix2 * ms);
void mat2_rmmul(Matrix2 * md, const Matrix2 * ms);
void mat2_tranpose(Matrix2 * md);
void vec2_mmul(Vector2 * vd, const Matrix2 * m, const Vector2 * vs);
void vec2_mimul(Vector2 * vd, const Matrix2 * m, const Vector2 * vs);
void mat2_set_rotate(Matrix2 * md, float a);
void mat2_rotate(Matrix2 * md, float a);
float mat2_det(const Matrix2 * ms);
void mat2_invert(Matrix2 * md, const Matrix2 * ms);
struct Vector3
{
float v[3];
};
inline void vec3_set(Vector3 * vd, float x, float y, float z);
void vec3_sum(Vector3 * vd, const Vector3 * v1, const Vector3 * v2);
void vec3_diff(Vector3 * vd, const Vector3 * v1, const Vector3 * v2);
void vec3_add(Vector3 * vd, const Vector3 * vs);
void vec3_sub(Vector3 * vd, const Vector3 * vs);
void vec3_madd(Vector3 * vd, float s, const Vector3 * vs);
void vec3_scale(Vector3 * vd, float s);
void vec3_lincomb(Vector3 * vd, const Vector3 * vb, float x, const Vector3 * vx);
void vec3_lincomb2(Vector3 * vd, const Vector3 * vb, float x, const Vector3 * vx, float y, const Vector3 * vy);
void vec3_lerp(Vector3 * vd, const Vector3 * v1, const Vector3 * v2, float t);
bool vec3_is_zero(const Vector3 * v);
float vec3_vmul(const Vector3 * v1, const Vector3 * v2);
void vec3_norm(Vector3 * v);
float vec3_length(const Vector3 * v);
float vec3_qlength(const Vector3 * v);
float vec3_distance(const Vector3 * v1, const Vector3 * v2);
float vec3_qdistance(const Vector3 * v1, const Vector3 * v2);
void vec3_mcadd(Vector3 * vd, const Vector3 * v1, const Vector3 * v2);
void vec3_mscadd(Vector3 * vd, float s, const Vector3 * v1, const Vector3 * v2);
void vec3_cmul(Vector3 * vd, const Vector3 * v1, const Vector3 * v2);
void vec3_xmul(Vector3 * vd, const Vector3 * v1, const Vector3 * v2);
void vec3_mbase(Vector3 * v1, Vector3 * v2, Vector3 * v3);
void vec3_bend(Vector3 * vd, const Vector3 * vs, float chi1, float chi2);
struct Matrix3
{
float m[9];
};
void mat3_ident(Matrix3 * m);
void mat3_scale(Matrix3 * md, float s);
void mat3_add(Matrix3 * md, const Matrix3 * ms);
void mat3_mmul(Matrix3 * md, const Matrix3 * ms);
void mat3_rmmul(Matrix3 * md, const Matrix3 * ms);
void mat3_transpose(Matrix3 * md, const Matrix3 * ms);
float mat3_det(const Matrix3 * ms);
void mat3_invert(Matrix3 * md, const Matrix3 * ms);
void vec3_mmul(Vector3 * vd, const Matrix3 * m, const Vector3 * vs);
void mat3_set_rotate_x(Matrix3 * m, float a);
void mat3_set_rotate_y(Matrix3 * m, float a);
void mat3_set_rotate_z(Matrix3 * m, float a);
void mat3_set_rotate(Matrix3 * m, const Vector3 * v, float a);
struct Vector4
{
float v[4];
};
inline void vec4_set(Vector4 * vd, float x, float y, float z, float w);
void vec4_sum(Vector4 * vd, const Vector4 * v1, const Vector4 * v2);
void vec4_diff(Vector4 * vd, const Vector4 * v1, const Vector4 * v2);
void vec4_add(Vector4 * vd, const Vector4 * vs);
void vec4_sub(Vector4 * vd, const Vector4 * vs);
void vec4_madd(Vector4 * vd, float s, const Vector4 * vs);
void vec4_scale(Vector4 * vd, float s);
void vec4_lincomb(Vector4 * vd, const Vector4 * vb, float x, const Vector4 * vx);
void vec4_lincomb2(Vector4 * vd, const Vector4 * vb, float x, const Vector4 * vx, float y, const Vector4 * vy);
void vec4_lerp(Vector4 * vd, const Vector4 * v1, const Vector4 * v2, float t);
bool vec4_is_zero(const Vector4 * v);
float vec4_vmul(const Vector4 * v1, const Vector4 * v2);
void vec4_norm(Vector4 * v);
float vec4_length(const Vector4 * v);
float vec4_qlength(const Vector4 * v);
float vec4_distance(const Vector4 * v1, const Vector4 * v2);
float vec4_qdistance(const Vector4 * v1, const Vector4 * v2);
void vec4_mcadd(Vector4 * vd, const Vector4 * v1, const Vector4 * v2);
void vec4_mscadd(Vector4 * vd, float s, const Vector4 * v1, const Vector4 * v2);
void vec4_cmul(Vector4 * vd, const Vector4 * v1, const Vector4 * v2);
void vec4_xmul(Vector4 * vd, const Vector4 * v1, const Vector4 * v2);
void vec4_mbase(Vector4 * v1, Vector4 * v2, Vector4 * v3);
void vec4_bend(Vector4 * vd, const Vector4 * vs, float chi1, float chi2);
struct Matrix4
{
float m[16];
};
void mat4_ident(Matrix4 * m);
void mat4_from_vec4(Matrix4 * m, const Vector4 * vx, const Vector4 * vy, const Vector4 * vz, const Vector4 * vw);
void mat4_from_vec3(Matrix4 * m, const Vector3 * vx, const Vector3 * vy, const Vector3 * vz, const Vector3 * vw);
void mat4_make_perspective(Matrix4 * m, float fieldOfViewInRadians, float aspect, float near, float far);
void mat4_make_view(Matrix4 * m, const Vector3 * pos, const Vector3 * target, const Vector3 * up);
void mat4_scale(Matrix4 * md, float s);
void mat4_add(Matrix4 * md, const Matrix4 * ms);
void mat4_mmul(Matrix4 * md, const Matrix4 * ms);
void mat4_rmmul(Matrix4 * md, const Matrix4 * ms);
float mat4_det(const Matrix4 * m);
void mat4_invert(Matrix4 * md, const Matrix4 * ms);
void vec4_mmul(Vector4 * vd, const Matrix4 * m, const Vector4 * vs);
void vec3_mmulp(Vector3 * vd, const Matrix4 * m, const Vector3 * vs);
void vec3_mmuld(Vector3 * vd, const Matrix4 * m, const Vector3 * vs);
void mat4_set_rotate_x(Matrix4 * m, float a);
void mat4_set_rotate_y(Matrix4 * m, float a);
void mat4_set_rotate_z(Matrix4 * m, float a);
void mat4_set_rotate(Matrix4 * m, const Vector3 * v, float a);
void mat4_set_translate(Matrix4 * m, const Vector3 * v);
void mat4_set_scale(Matrix4 * m, float s);
void vec3_project(Vector3 * vd, const Matrix4 * m, const Vector3 * vs);
// And now for some fixpoint math in 4.12
struct F12Vector3
{
int v[3];
};
struct F12Matrix3
{
int m[9];
};
static const int FIX12_ONE = 1 << 12;
void f12mat3_ident(F12Matrix3 * m);
void f12mat3_mmul(F12Matrix3 * md, const F12Matrix3 * ms);
void f12mat3_rmmul(F12Matrix3 * md, const F12Matrix3 * ms);
void f12mat3_set_rotate_x(F12Matrix3 * m, float a);
void f12mat3_set_rotate_y(F12Matrix3 * m, float a);
void f12mat3_set_rotate_z(F12Matrix3 * m, float a);
void f12vec3_mmul(F12Vector3 * vd, const F12Matrix3 * m, const F12Vector3 * vs);
#pragma compile("vector3d.c")
#endif
+26
View File
@@ -0,0 +1,26 @@
#include "inttypes.h"
#include "stdlib.h"
intmax_t imaxabs(intmax_t n)
{
return n < 0 ? -n : n;
}
imaxdiv_t imaxdiv(intmax_t l, intmax_t r)
{
imaxdiv_t t;
t.quot = l / r;
t.rem = l % r;
return t;
}
inline intmax_t strtoimax(const char * s, char ** endp, int base)
{
return strtol(s, endp, base);
}
inline uintmax_t strtoumax(const char * s, char ** endp, int base)
{
return strtoul(s, endp, base);
}
+98
View File
@@ -0,0 +1,98 @@
#ifndef INTTYPES_H
#define INTTYPES_H
#include <stdint.h>
#define PRId8 "d"
#define PRId16 "d"
#define PRId32 "ld"
#define PRIdLEAST8 "d"
#define PRIdLEAST16 "d"
#define PRIdLEAST32 "ld"
#define PRIdFAST8 "d"
#define PRIdFAST16 "d"
#define PRIdFAST32 "ld"
#define PRIdMAX "ld"
#define PRIdPTR "d"
#define PRIo8 "o"
#define PRIo16 "o"
#define PRIo32 "lo"
#define PRIoLEAST8 "o"
#define PRIoLEAST16 "o"
#define PRIoLEAST32 "lo"
#define PRIoFAST8 "o"
#define PRIoFAST16 "o"
#define PRIoFAST32 "lo"
#define PRIoMAX "lo"
#define PRIoPTR "o"
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "lu"
#define PRIuLEAST8 "u"
#define PRIuLEAST16 "u"
#define PRIuLEAST32 "lu"
#define PRIuFAST8 "u"
#define PRIuFAST16 "u"
#define PRIuFAST32 "lu"
#define PRIuMAX "lu"
#define PRIuPTR "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "lx"
#define PRIxLEAST8 "x"
#define PRIxLEAST16 "x"
#define PRIxLEAST32 "lx"
#define PRIxFAST8 "x"
#define PRIxFAST16 "x"
#define PRIxFAST32 "lx"
#define PRIxMAX "lx"
#define PRIxPTR "x"
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIX32 "lX"
#define PRIXLEAST8 "X"
#define PRIXLEAST16 "X"
#define PRIXLEAST32 "lX"
#define PRIXFAST8 "X"
#define PRIXFAST16 "X"
#define PRIXFAST32 "lX"
#define PRIXMAX "lX"
#define PRIXPTR "X"
typedef struct {
intmax_t quot;
intmax_t rem;
} imaxdiv_t;
intmax_t imaxabs(intmax_t n);
imaxdiv_t imaxdiv(intmax_t l, intmax_t r);
intmax_t strtoimax(const char * s, char ** endp, int base);
uintmax_t strtoumax(const char * s, char ** endp, int base);
#pragma compile("inttypes.c")
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef ISO646_H
#define ISO646_H
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=
#endif
+18
View File
@@ -0,0 +1,18 @@
#ifndef LIMITS_H
#define LIMITS_H
#define CHAR_BIT 8
#define SCHAR_MIN -128
#define SCHAR_MAX 127
#define UCHAR_MAX 255
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#define INT_MIN (-32767-1)
#define INT_MAX 32767
#define UINT_MAX 65535
#endif
+239
View File
@@ -0,0 +1,239 @@
#include "math.h"
#include "stdio.h"
float cos(float f)
{
return sin(f + 0.5 * PI);
}
#define F_SIN_1 6.283168
#define F_SIN_2 0.053878661
#define F_SIN_3 -42.5385038
#define F_SIN_4 9.23583223
#define F_SIN_5 55.7310503
float sin(float f)
{
float g = fabs(f);
float m = f < 0.0 ? -1.0 : 1.0;
g *= 0.5 / PI;
g -= floor(g);
if (g >= 0.5)
{
m = -m;
g -= 0.5;
}
if (g >= 0.25)
g = 0.5 - g;
float s = F_SIN_5;
s *= g; s += F_SIN_4;
s *= g; s += F_SIN_3;
s *= g; s += F_SIN_2;
s *= g; s += F_SIN_1;
s *= g;
return s * m;
}
float tan(float f)
{
return sin(f) / cos(f);
}
float acos(float f)
{
return atan2(sqrt(1.0 - f * f), f);
}
float asin(float f)
{
return atan2(f, sqrt(1.0 - f * f));
}
float atan(float f)
{
return atan2(f, 1.0);
}
#define F_ATAN_0 -6.435678E-5
#define F_ATAN_1 0.999648382
#define F_ATAN_2 0.018278903
#define F_ATAN_3 -0.444599298
#define F_ATAN_4 0.263177486
#define F_ATAN_5 -0.051078392
float atan2(float p, float q)
{
int quad = 0;
if (p < 0)
{
quad |= 4;
p = -p;
}
if (q < 0)
{
quad |= 2;
q = -q;
}
float g;
if (p > q)
{
g = q / p;
quad |= 1;
}
else
{
g = p / q;
}
float s = F_ATAN_5;
s *= g; s += F_ATAN_4;
s *= g; s += F_ATAN_3;
s *= g; s += F_ATAN_2;
s *= g; s += F_ATAN_1;
s *= g; s += F_ATAN_0;
if (quad & 1)
s = 0.5 * PI - s;
if (quad & 2)
s = PI - s;
if (quad & 4)
s = -s;
return s;
}
#define F_EXP_0 1.0
#define F_EXP_1 0.69315668
#define F_EXP_2 0.240132068
#define F_EXP_3 0.055876024
#define F_EXP_4 0.008940801
#define F_EXP_5 0.001894414
float exp(float f)
{
f *= 1.442695041;
float ff = floor(f), g = f - ff;
int fi = (int)ff;
union {
float f;
int i[2];
} x;
x.f = 0;
x.i[1] = (fi + 0x7f) << 7;
float s = F_EXP_5;
s *= g; s += F_EXP_4;
s *= g; s += F_EXP_3;
s *= g; s += F_EXP_2;
s *= g; s += F_EXP_1;
s *= g; s += F_EXP_0;
return s * x.f;
}
#define F_LOG_0 -3.78717706
#define F_LOG_1 10.0960498
#define F_LOG_2 -13.975654
#define F_LOG_3 12.7580616
#define F_LOG_4 -6.48190725
#define F_LOG_5 1.39064767
float log(float f)
{
if (f == 0.0)
return 1.0;
union {
float f;
int i[2];
} x;
x.f = f;
int ei = x.i[1];
int ex = (ei >> 7) - 0x7e;
x.i[1] = (ei & 0x007f) | 0x3f00;
float g = x.f;
float fex = ex;
float s = F_LOG_5;
s *= g; s += F_LOG_4;
s *= g; s += F_LOG_3;
s *= g; s += F_LOG_2;
s *= g; s += F_LOG_1;
s *= g; s += F_LOG_0;
return (fex + s) * 0.6931471806;
}
float log10(float f)
{
return log(f) * 0.4342944819;
}
float pow(float p, float q)
{
return exp(q * log(p));
}
float sqrt(float f)
{
if (f >= 0)
{
union {
float f;
int i[2];
} x;
x.f = f;
int ex = (x.i[1] >> 7) - 0x7f;
ex /= 2;
x.i[1] = (ex + 0x7f) << 7;
float fq = x.f;
fq = 0.5 * (fq + f / fq);
fq = 0.5 * (fq + f / fq);
fq = 0.5 * (fq + f / fq);
fq = 0.5 * (fq + f / fq);
return fq;
}
else
return 0.0;
}
bool isinf(float f)
{
union {
float f;
unsigned i[2];
} x;
x.f = f;
return ((x.i[1] >> 7) & 0xff) == 0xff;
}
bool isfinite(float f)
{
union {
float f;
unsigned i[2];
} x;
x.f = f;
return ((x.i[1] >> 7) & 0xff) != 0xff;
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef MATH_H
#define MATH_H
#define PI 3.141592653
float fabs(float f);
float floor(float f);
float ceil(float f);
float cos(float f);
float sin(float f);
float tan(float f);
float acos(float f);
float asin(float f);
float atan(float f);
float atan2(float p, float q);
float exp(float f);
float log(float f);
float log10(float f);
float pow(float p, float q);
float sqrt(float f);
bool isinf(float f);
bool isfinite(float f);
#pragma intrinsic(fabs)
#pragma intrinsic(floor)
#pragma intrinsic(ceil)
#pragma intrinsic(sin)
#pragma intrinsic(cos)
#pragma intrinsic(tan)
#pragma intrinsic(atan)
#pragma intrinsic(atan2)
#pragma intrinsic(log)
#pragma intrinsic(exp)
#pragma intrinsic(pow)
#pragma intrinsic(sqrt)
#pragma compile("math.c")
#endif
+60
View File
@@ -0,0 +1,60 @@
#include "mmc1.h"
void mmc1_reset(void)
{
*(volatile char *)0x8000 = 0x80;
}
void mmc1_config(MMC1Mirror mirror, MMC1MPrgMode pmode, MMC1MChrMode cmode)
{
char reg = mirror | (pmode << 2) | (cmode << 4);
*(volatile char *)0x8000 = reg;
reg >>= 1;
*(volatile char *)0x8000 = reg;
reg >>= 1;
*(volatile char *)0x8000 = reg;
reg >>= 1;
*(volatile char *)0x8000 = reg;
reg >>= 1;
*(volatile char *)0x8000 = reg;
}
void mmc1_bank_prg(char bank)
{
*(volatile char *)0xe000 = bank;
bank >>= 1;
*(volatile char *)0xe000 = bank;
bank >>= 1;
*(volatile char *)0xe000 = bank;
bank >>= 1;
*(volatile char *)0xe000 = bank;
bank >>= 1;
*(volatile char *)0xe000 = bank;
}
void mmc1_bank_chr0(char bank)
{
*(volatile char *)0xa000 = bank;
bank >>= 1;
*(volatile char *)0xa000 = bank;
bank >>= 1;
*(volatile char *)0xa000 = bank;
bank >>= 1;
*(volatile char *)0xa000 = bank;
bank >>= 1;
*(volatile char *)0xa000 = bank;
}
void mmc1_bank_chr1(char bank)
{
*(volatile char *)0xc000 = bank;
bank >>= 1;
*(volatile char *)0xc000 = bank;
bank >>= 1;
*(volatile char *)0xc000 = bank;
bank >>= 1;
*(volatile char *)0xc000 = bank;
bank >>= 1;
*(volatile char *)0xc000 = bank;
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef NES_MMC1_H
#define NES_MMC1_H
#include <c64/types.h>
enum MMC1Mirror
{
MMC1M_LOWER,
MMC1M_UPPER,
MMC1M_VERTICAL,
MMC1M_HORIZONTAL
};
enum MMC1MPrgMode
{
MMC1P_32K,
MMC1P_32Kx,
MMC1P_16K_UPPER,
MMC1P_16K_LOWER
};
enum MMC1MChrMode
{
MMC1C_8K,
MMC1C_4Kx,
};
void mmc1_reset(void);
void mmc1_config(MMC1Mirror mirror, MMC1MPrgMode pmode, MMC1MChrMode cmode);
void mmc1_bank_prg(char bank);
void mmc1_bank_chr0(char bank);
void mmc1_bank_chr1(char bank);
#pragma compile("mmc1.c")
#endif
+36
View File
@@ -0,0 +1,36 @@
#include "mmc3.h"
char mmc3_shadow;
void mmc3_reset(void)
{
mmc3_shadow = 0;
}
void mmc3_config(MMC3MPrgMode pmode, MMC3MChrMode cmode)
{
mmc3_shadow = (pmode << 6) | (cmode << 7);
*(volatile char *)0x8000 = mmc3_shadow;
}
void mmc3_bank(MMC3BankReg reg, char bank)
{
*(volatile char *)0x8000 = reg | mmc3_shadow;
*(volatile char *)0x8001 = bank;
}
void mmc3_bank_prg(char bank)
{
mmc3_bank(MMC3B_PRG0, bank * 2 + 0);
mmc3_bank(MMC3B_PRG1, bank * 2 + 1);
}
void mmc3_bank_chr0(char bank)
{
mmc3_bank(MMC3B_CHR0, bank);
}
void mmc3_bank_chr1(char bank)
{
mmc3_bank(MMC3B_CHR1, bank);
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef NES_MMC3_H
#define NES_MMC3_H
#include <c64/types.h>
enum MMC3MPrgMode
{
MMC3P_8K_LOWER,
MMC3P_8K_UPPER
};
enum MMC3MChrMode
{
MMC3C_2K_LOWER,
MMC3C_2K_HIGHER,
};
enum MMC3BankReg
{
MMC3B_CHR0,
MMC3B_CHR1,
MMC3B_CHR2,
MMC3B_CHR3,
MMC3B_CHR4,
MMC3B_CHR5,
MMC3B_PRG0,
MMC3B_PRG1
};
extern char mmc3_shadow;
void mmc3_reset(void);
void mmc3_config(MMC3MPrgMode pmode, MMC3MChrMode cmode);
inline void mmc3_bank(MMC3BankReg reg, char bank);
void mmc3_bank_prg(char bank);
void mmc3_bank_chr0(char bank);
void mmc3_bank_chr1(char bank);
#pragma compile("mmc3.c")
#endif
+2
View File
@@ -0,0 +1,2 @@
#include "nes.h"
+76
View File
@@ -0,0 +1,76 @@
#ifndef NES_NES_H
#define NES_NES_H
#include <c64/types.h>
#define PPU_CTRL_NT_2000 0b00000000
#define PPU_CTRL_NT_2400 0b00000001
#define PPU_CTRL_NT_2800 0b00000010
#define PPU_CTRL_NT_2C00 0b00000011
#define PPU_CTRL_INC_1 0b00000000
#define PPU_CTRL_INC_32 0b00000100
#define PPU_CTRL_SPR_0000 0b00000000
#define PPU_CTRL_SPR_1000 0b00001000
#define PPU_CTRL_BG_0000 0b00000000
#define PPU_CTRL_BG_1000 0b00010000
#define PPU_CTRL_SPR_8X8 0b00000000
#define PPU_CTRL_SPR_8X16 0b00100000
#define PPU_CTRL_NMI 0b10000000
#define PPU_MASK_GREYSCALE 0b00000001
#define PPU_MASK_BG8 0b00000010
#define PPU_MASK_SPR8 0b00000100
#define PPU_MASK_BG_ON 0b00001000
#define PPU_MASK_SPR_ON 0b00010000
#define PPU_MASK_EM_RED 0b00100000
#define PPU_MASK_EM_GREEN 0b01000000
#define PPU_MASK_EM_BLUE 0b10000000
struct PPU
{
volatile byte control;
volatile byte mask;
volatile byte status;
volatile byte oamaddr;
volatile byte oamdata;
volatile byte scroll;
volatile byte addr;
volatile byte data;
};
#define ppu (*((struct PPU *)0x2000))
struct NESIO
{
volatile byte sq1_volume;
volatile byte sq1_sweep;
volatile word sq1_freq;
volatile byte sq2_volume;
volatile byte sq2_sweep;
volatile word sq2_freq;
volatile byte tri_volume;
volatile byte tri_pad;
volatile word tri_freq;
volatile byte noise_volume;
volatile byte noise_pad;
volatile word noise_freq;
volatile byte dmc_freq;
volatile byte dmc_raw;
volatile byte dmc_start;
volatile byte dmc_length;
volatile byte oamdma;
volatile byte channels;
volatile byte input[2];
};
#define nesio (*((struct NESIO *)0x4000))
#pragma compile("nes.c")
#endif
+667
View File
@@ -0,0 +1,667 @@
#include "neslib.h"
// NES hardware-dependent functions by Shiru (shiru@mail.ru)
// with improvements by VEG
// Feel free to do anything you want with this code, consider it Public Domain
const char palBrightTable[] = {
0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0f,0x0f,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x00,0x00,0x00,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x10,0x10,0x10,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x20,0x20,0x20,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30
};
volatile char OAM_BUF[256];
volatile char PAL_BUF[32];
#pragma align(OAM_BUF, 256)
char NTSC_MODE;
volatile char FRAME_CNT1;
volatile char FRAME_CNT2;
volatile char VRAM_UPDATE;
char * volatile NAME_UPD_ADR;
volatile char NAME_UPD_ENABLE;
volatile char PAL_UPDATE;
const char *volatile PAL_BG_PTR;
const char *volatile PAL_SPR_PTR;
volatile char SCROLL_X;
volatile char SCROLL_Y;
char SCROLL_X1;
char SCROLL_Y1;
char PAD_STATE[2];
char PAD_STATEP[2];
char PAD_STATET[2];
volatile char PPU_CTRL_VAR;
char PPU_CTRL_VAR1;
volatile char PPU_MASK_VAR;
char RAND_SEED[2];
int main(void)
{
ppu.mask = 0;
nesio.dmc_freq = 0;
ppu.control = 0;
char c = ppu.status;
do {} while (!(ppu.status & 0x80));
do {} while (!(ppu.status & 0x80));
nesio.input[1] = 0x40;
ppu.addr = 0x3f;
ppu.addr = 0x00;
for(char i=0; i<32; i++)
ppu.data = 0x0f;
ppu.addr = 0x20;
ppu.addr = 0x00;
for(unsigned i=0; i<0x1000; i++)
ppu.data = 0x00;
char i = 0;
do {
((char *)0x200)[i] = 0;
((char *)0x300)[i] = 0;
((char *)0x400)[i] = 0;
((char *)0x500)[i] = 0;
((char *)0x600)[i] = 0;
((char *)0x700)[i] = 0;
i++;
} while (i);
pal_bright(4);
pal_clear();
oam_clear();
PPU_CTRL_VAR = 0x80;
PPU_MASK_VAR = 0x06;
ppu.control = 0x80;
RAND_SEED[0] = 0xfd;
RAND_SEED[1] = 0xfd;
ppu.scroll = 0x00;
ppu.scroll = 0x00;
ppu.oamaddr = 0x00;
// detect PAL or NTSC based on Blarg code.
ppu_wait_nmi();
__asm {
ldx #52
ldy #24
system_check_wait:
dex
bne system_check_wait
dey
bne system_check_wait
lda $2002
and #$80
sta NTSC_MODE
}
nes_game();
return 0;
}
__hwinterrupt void nmi(void)
{
if (PPU_MASK_VAR & 0x18)
{
nesio.oamdma = (unsigned)(&OAM_BUF[0]) >> 8;
if (PAL_UPDATE)
{
PAL_UPDATE = 0;
ppu.addr = 0x3f;
ppu.addr = 0x00;
char c = PAL_BG_PTR[PAL_BUF[0]];
ppu.data = c;
ppu.data = PAL_BG_PTR[PAL_BUF[1]];
ppu.data = PAL_BG_PTR[PAL_BUF[2]];
ppu.data = PAL_BG_PTR[PAL_BUF[3]];
#pragma unroll(full)
for(char j=0; j<3; j++)
{
ppu.data = c;
ppu.data = PAL_BG_PTR[PAL_BUF[5 + 4 * j + 0]];
ppu.data = PAL_BG_PTR[PAL_BUF[5 + 4 * j + 1]];
ppu.data = PAL_BG_PTR[PAL_BUF[5 + 4 * j + 2]];
}
#pragma unroll(full)
for(char j=0; j<4; j++)
{
ppu.data = c;
ppu.data = PAL_SPR_PTR[PAL_BUF[17 + 4 * j + 0]];
ppu.data = PAL_SPR_PTR[PAL_BUF[17 + 4 * j + 1]];
ppu.data = PAL_SPR_PTR[PAL_BUF[17 + 4 * j + 2]];
}
}
if (VRAM_UPDATE)
{
VRAM_UPDATE = 0;
if (NAME_UPD_ENABLE)
flush_vram_update(NAME_UPD_ADR);
}
ppu.addr = 0x00;
ppu.addr = 0x00;
ppu.scroll = SCROLL_X;
ppu.scroll = SCROLL_Y;
ppu.control = PPU_CTRL_VAR;
}
ppu.mask = PPU_MASK_VAR;
FRAME_CNT1++;
FRAME_CNT2++;
if (FRAME_CNT2 == 6)
FRAME_CNT2 = 0;
// jsr FamiToneUpdate
}
void pal_all(const char *data)
{
for(char i=0; i<32; i++)
PAL_BUF[i] = data[i];
PAL_UPDATE++;
}
void pal_bg(const char *data)
{
for(char i=0; i<16; i++)
PAL_BUF[i] = data[i];
PAL_UPDATE++;
}
void pal_spr(const char *data)
{
for(char i=0; i<16; i++)
PAL_BUF[i + 16] = data[i];
PAL_UPDATE++;
}
void pal_col(unsigned char index,unsigned char color)
{
PAL_BUF[index & 0x1f] = color;
PAL_UPDATE++;
}
void pal_clear(void)
{
for(char i=0; i<32; i++)
PAL_BUF[i] = 0x0f;
PAL_UPDATE++;
}
void pal_spr_bright(unsigned char bright)
{
PAL_SPR_PTR = palBrightTable + 16 * bright;
PAL_UPDATE++;
}
void pal_bg_bright(unsigned char bright)
{
PAL_BG_PTR = palBrightTable + 16 * bright;
PAL_UPDATE++;
}
void pal_bright(unsigned char bright)
{
pal_spr_bright(bright);
pal_bg_bright(bright);
}
void ppu_off(void)
{
PPU_MASK_VAR &= 0b11100111;
ppu_wait_nmi();
}
void ppu_on_all(void)
{
PPU_MASK_VAR|= 0b00011000;
ppu_wait_nmi();
}
void ppu_on_bg(void)
{
PPU_MASK_VAR |= 0b00001000;
ppu_wait_nmi();
}
void ppu_on_spr(void)
{
PPU_MASK_VAR |= 0b00010000;
ppu_wait_nmi();
}
void ppu_mask(unsigned char mask)
{
PPU_MASK_VAR = mask;
}
unsigned char ppu_system(void)
{
return NTSC_MODE;
}
unsigned char get_ppu_ctrl_var(void)
{
return PPU_CTRL_VAR;
}
void set_ppu_ctrl_var(unsigned char var)
{
PPU_CTRL_VAR = var;
}
void oam_clear(void)
{
char i = 0;
do {
OAM_BUF[i] = 255; // off screen not top corner.
i += 4;
} while (i);
}
void oam_size(unsigned char size)
{
if (size & 1)
PPU_CTRL_VAR |= 0x20;
else
PPU_CTRL_VAR &= ~0x20;
}
unsigned char oam_spr(unsigned char x,unsigned char y,unsigned char chrnum,unsigned char attr,unsigned char sprid)
{
OAM_BUF[sprid + 2] = attr;
OAM_BUF[sprid + 1] = chrnum;
OAM_BUF[sprid + 0] = y;
OAM_BUF[sprid + 3] = x;
return sprid + 4;
}
unsigned char oam_meta_spr(unsigned char x,unsigned char y,unsigned char sprid,const unsigned char *data)
{
char i = 0;
while (data[i] != 0x80)
{
OAM_BUF[sprid + 3] = x + data[i + 0];
OAM_BUF[sprid + 0] = y + data[i + 1];
OAM_BUF[sprid + 1] = data[i + 2];
OAM_BUF[sprid + 2] = data[i + 3];
sprid += 4;
i += 4;
}
return sprid;
}
void oam_hide_rest(unsigned char sprid)
{
do {
OAM_BUF[sprid] = 240;
sprid += 4;
} while (sprid);
}
void ppu_wait_frame(void)
{
VRAM_UPDATE = 1;
char c = FRAME_CNT1;
while (c == FRAME_CNT1) ;
if (NTSC_MODE)
{
while (FRAME_CNT2 == 5) ;
}
}
void ppu_wait_nmi(void)
{
VRAM_UPDATE = 1;
char c = FRAME_CNT1;
while (c == FRAME_CNT1) ;
}
void vram_unrle(const unsigned char *data)
{
char tag = *data++;
char b;
for(;;)
{
char c = *data++;
if (c != tag)
{
ppu.data = c;
b = c;
}
else
{
c = *data++;
if (!c)
return;
while (c)
{
ppu.data = b;
c--;
}
}
}
}
void scroll(unsigned int x,unsigned int y)
{
char b = (PPU_CTRL_VAR & 0xfc) | ((x >> 8) & 1);
if (y >= 240)
{
y -= 240;
b |= 2;
}
SCROLL_Y = y;
SCROLL_X = x;
PPU_CTRL_VAR = b;
}
void split(unsigned int x,unsigned int y)
{
char b = (PPU_CTRL_VAR & 0xfc) | ((x >> 8) & 1);
SCROLL_X1 = x;
PPU_CTRL_VAR1 = b;
while (ppu.status & 0x40) ;
while (!(ppu.status & 0x40)) ;
ppu.scroll = SCROLL_X1;
ppu.scroll = 0;
ppu.control = PPU_CTRL_VAR1;
}
void bank_spr(unsigned char n)
{
if (n & 1)
PPU_CTRL_VAR |= 0x08;
else
PPU_CTRL_VAR &= ~0x08;
}
void bank_bg(unsigned char n)
{
if (n & 1)
PPU_CTRL_VAR |= 0x10;
else
PPU_CTRL_VAR &= ~0x10;
}
void vram_read(unsigned char *dst,unsigned int size)
{
for(unsigned i=size; i!=0; i--)
*dst++ = ppu.data;
}
void vram_write(const unsigned char *src,unsigned int size)
{
for(unsigned i=size; i!=0; i--)
ppu.data = *src++;
}
void music_play(unsigned char song)
{
//_music_play=FamiToneMusicPlay
}
void music_stop(void)
{
//_music_stop=FamiToneMusicStop
}
void music_pause(unsigned char pause)
{
//_music_pause=FamiToneMusicPause
}
void sfx_play(unsigned char sound,unsigned char channel)
{
#if 0
_sfx_play:
.if(FT_SFX_ENABLE)
and #$03
tax
lda @sfxPriority,x
tax
jsr popa
jmp FamiToneSfxPlay
@sfxPriority:
.byte FT_SFX_CH0,FT_SFX_CH1,FT_SFX_CH2,FT_SFX_CH3
.else
rts
.endif
#endif
}
void sample_play(unsigned char sample)
{
#if 0
.if(FT_DPCM_ENABLE)
_sample_play=FamiToneSamplePlay
.else
_sample_play:
rts
.endif
#endif
}
unsigned char pad_poll(unsigned char pad)
{
char buf[3];
for(char j=0; j<3; j++)
{
nesio.input[0] = 1;
nesio.input[0] = 0;
char c = 0;
for(char i=0; i<8; i++)
{
c = (c | (nesio.input[pad] << 8)) >> 1;
}
buf[j] = c;
}
char b = buf[0];
if (b != buf[1] && b != buf[2])
b = buf[1];
PAD_STATE[pad] = b;
PAD_STATET[pad] = (b ^ PAD_STATEP[pad]) & PAD_STATE[pad];
PAD_STATEP[pad] = b;
return b;
}
unsigned char pad_trigger(unsigned char pad)
{
pad_poll(pad);
return PAD_STATET[pad];
}
unsigned char pad_state(unsigned char pad)
{
return PAD_STATE[pad];
}
unsigned char rand1(void)
{
if (RAND_SEED[0] & 0x80)
{
RAND_SEED[0] <<= 1;
RAND_SEED[0] ^= 0xcf;
}
else
RAND_SEED[0] <<= 1;
return RAND_SEED[0];
}
unsigned char rand2(void)
{
if (RAND_SEED[1] & 0x80)
{
RAND_SEED[1] <<= 1;
RAND_SEED[1] ^= 0xd7;
}
else
RAND_SEED[1] <<= 1;
return RAND_SEED[1];
}
unsigned char rand8(void)
{
return rand1() + rand2();
}
unsigned int rand16(void)
{
return (rand1() << 8) | rand2();
}
void set_rand(unsigned seed)
{
RAND_SEED[0] = seed & 0xff;
RAND_SEED[1] = seed >> 8;
}
void set_vram_update(unsigned char *buf)
{
NAME_UPD_ADR = buf;
NAME_UPD_ENABLE = buf != nullptr;
}
void flush_vram_update(unsigned char *buf)
{
char i = 0;
for(;;)
{
char c = buf[i++];
if (c < 0x40)
{
ppu.addr = c;
ppu.addr = buf[i++];
ppu.data = buf[i++];
}
else
{
if (c < 0x80)
ppu.control = PPU_CTRL_VAR & ~0x04;
else if (c != 0xff)
ppu.control = PPU_CTRL_VAR | 0x04;
else
return;
ppu.addr = c & 0x3f;
ppu.addr = buf[i++];
c = buf[i++];
do {
ppu.data = buf[i++];
c--;
} while (c);
ppu.control = PPU_CTRL_VAR;
}
}
}
void vram_adr(unsigned int addr)
{
ppu.addr = addr >> 8;
ppu.addr = addr & 0xff;
}
void vram_put(unsigned char n)
{
ppu.data = n;
}
void vram_fill(unsigned char n,unsigned int size)
{
for(unsigned i=size; i!=0; i--)
ppu.data = n;
}
void vram_inc(unsigned char n)
{
if (n)
PPU_CTRL_VAR |= 0x04;
else
PPU_CTRL_VAR &= ~0x04;
ppu.control = PPU_CTRL_VAR;
}
void memfill(void *dst,unsigned char value,unsigned int size)
{
for(unsigned i=size; i!=0; i--)
*dst++ = value;
}
unsigned char nesclock(void)
{
return FRAME_CNT1;
}
void delay(unsigned char frames)
{
while (frames)
{
ppu_wait_nmi();
frames--;
}
}
#pragma data(boot)
__export struct Boot
{
void * nmi, * reset, * irq;
} boot = {
nmi,
(void *)0xff80,
nullptr
};
#pragma data(data)
+295
View File
@@ -0,0 +1,295 @@
#ifndef NES_NESLIB_H
#define NES_NESLIB_H
#include "nes.h"
/*
(C) 2015 Alex Semenov (Shiru)
(C) 2016 Lauri Kasanen
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// NES hardware-dependent functions by Shiru (shiru@mail.ru)
// Feel free to do anything you want with this code, consider it Public Domain
// Versions history:
// 280215 - fixed palette glitch caused with the active DMC DMA glitch
// 030914 - minor fixes in the vram update system
// 310814 - added vram_flush_update
// 120414 - removed adr argument from vram_write and vram_read,
// unrle_vram renamed to vram_unrle, with adr argument removed
// 060414 - many fixes and improvements, including sequental VRAM updates
// previous versions were created since mid-2011, there were many updates
void nes_game(void);
// set bg and spr palettes, data is 32 bytes array
void pal_all(const char *data);
// set bg palette only, data is 16 bytes array
void pal_bg(const char *data);
// set spr palette only, data is 16 bytes array
void pal_spr(const char *data);
// set a palette entry, index is 0..31
inline void pal_col(unsigned char index, unsigned char color);
// reset palette to $0f
void pal_clear(void);
// set virtual bright both for sprites and background, 0 is black, 4 is normal, 8 is white
void pal_bright(unsigned char bright);
// set virtual bright for sprites only
void pal_spr_bright(unsigned char bright);
// set virtual bright for sprites background only
void pal_bg_bright(unsigned char bright);
// wait actual TV frame, 50hz for PAL, 60hz for NTSC
void ppu_wait_nmi(void);
// wait virtual frame, it is always 50hz, frame-to-frame in PAL, frameskip in NTSC
void ppu_wait_frame(void);
// turn off rendering, nmi still enabled when rendering is disabled
void ppu_off(void);
// turn on bg, spr
void ppu_on_all(void);
// turn on bg only
void ppu_on_bg(void);
// turn on spr only
void ppu_on_spr(void);
// set PPU_MASK directly
inline void ppu_mask(unsigned char mask);
// get current video system, 0 for PAL, not 0 for NTSC
unsigned char ppu_system(void);
// Return an 8-bit counter incremented at each vblank
unsigned char nesclock(void);
// get/set the internal ppu ctrl cache var for manual writing
inline unsigned char get_ppu_ctrl_var(void);
inline void set_ppu_ctrl_var(unsigned char var);
// clear OAM buffer, all the sprites are hidden
void oam_clear(void);
// set sprite display mode, 0 for 8x8 sprites, 1 for 8x16 sprites
inline void oam_size(unsigned char size);
// set sprite in OAM buffer, chrnum is tile, attr is attribute, sprid is offset in OAM in bytes
// returns sprid+4, which is offset for a next sprite
inline unsigned char oam_spr(unsigned char x, unsigned char y,
unsigned char chrnum, unsigned char attr,
unsigned char sprid);
// set metasprite in OAM buffer
// meta sprite is a const unsigned char array, it contains four bytes per sprite
// in order x offset, y offset, tile, attribute
// x=128 is end of a meta sprite
// returns sprid+4, which is offset for a next sprite
unsigned char oam_meta_spr(unsigned char x, unsigned char y,
unsigned char sprid, const unsigned char *data);
// hide all remaining sprites from given offset
void oam_hide_rest(unsigned char sprid);
// play a music in FamiTone format
void music_play(unsigned char song);
// stop music
void music_stop(void);
// pause and unpause music
void music_pause(unsigned char pause);
// play FamiTone sound effect on channel 0..3
void sfx_play(unsigned char sound, unsigned char channel);
// play a DPCM sample, 1..63
void sample_play(unsigned char sample);
// poll controller and return flags like PAD_LEFT etc, input is pad number (0 or 1)
unsigned char pad_poll(unsigned char pad);
// poll controller in trigger mode, a flag is set only on button down, not hold
// if you need to poll the pad in both normal and trigger mode, poll it in the
// trigger mode for first, then use pad_state
unsigned char pad_trigger(unsigned char pad);
// get previous pad state without polling ports
inline unsigned char pad_state(unsigned char pad);
// set scroll, including rhe top bits
// it is always applied at beginning of a TV frame, not at the function call
void scroll(unsigned int x, unsigned int y);
// set scroll after screen split invoked by the sprite 0 hit
// warning: all CPU time between the function call and the actual split point will be wasted!
// warning: the program loop has to fit into the frame time, ppu_wait_frame should not be used
// otherwise empty frames without split will be inserted, resulting in jumpy screen
// warning: only X scroll could be changed in this version
void split(unsigned int x, unsigned int y);
// select current chr bank for sprites, 0..1
void bank_spr(unsigned char n);
// select current chr bank for background, 0..1
void bank_bg(unsigned char n);
// get random number 0..255 or 0..65535
unsigned char rand8(void);
unsigned int rand16(void);
// set random seed
void set_rand(unsigned int seed);
// when display is enabled, vram access could only be done with this vram update system
// the function sets a pointer to the update buffer that contains data and addresses
// in a special format. It allows to write non-sequental bytes, as well as horizontal or
// vertical nametable sequences.
// buffer pointer could be changed during rendering, but it only takes effect on a new frame
// number of transferred bytes is limited by vblank time
// to disable updates, call this function with NULL pointer
// the update data format:
// MSB, LSB, byte for a non-sequental write
// MSB|NT_UPD_HORZ, LSB, LEN, [bytes] for a horizontal sequence
// MSB|NT_UPD_VERT, LSB, LEN, [bytes] for a vertical sequence
// NT_UPD_EOF to mark end of the buffer
// length of this data should be under 256 bytes
inline void set_vram_update(unsigned char *buf);
// all following vram functions only work when display is disabled
// do a series of VRAM writes, the same format as for set_vram_update, but writes done right away
void flush_vram_update(unsigned char *buf);
// set vram pointer to write operations if you need to write some data to vram
inline void vram_adr(unsigned int adr);
// put a byte at current vram address, works only when rendering is turned off
inline void vram_put(unsigned char n);
// fill a block with a byte at current vram address, works only when rendering is turned off
void vram_fill(unsigned char n, unsigned int len);
// set vram autoincrement, 0 for +1 and not 0 for +32
inline void vram_inc(unsigned char n);
// read a block from current address of vram, works only when rendering is turned off
void vram_read(unsigned char *dst, unsigned int size);
// write a block to current address of vram, works only when rendering is turned off
void vram_write(const unsigned char *src, unsigned int size);
// unpack RLE data to current address of vram, mostly used for nametables
void vram_unrle(const unsigned char *data);
// unpack LZ4 data to this address
void vram_unlz4(const unsigned char *in, unsigned char *out,
const unsigned uncompressed_size);
/*
Rough speeds for a full 1024 nametable:
- rle takes 0.5 frames
- uncompressed takes 1.3 frames
- lz4 takes 2.8 frames
*/
// like memset, but does not return anything
void memfill(void *dst, unsigned char value, unsigned int len);
// delay for N frames
void delay(unsigned char frames);
// display.sinc functions
void oam_clear_fast(void);
void oam_meta_spr_pal(unsigned char x,unsigned char y,unsigned char pal,const unsigned char *metasprite);
void oam_meta_spr_clip(signed int x,unsigned char y,const unsigned char *metasprite);
#define PAD_A 0x01
#define PAD_B 0x02
#define PAD_SELECT 0x04
#define PAD_START 0x08
#define PAD_UP 0x10
#define PAD_DOWN 0x20
#define PAD_LEFT 0x40
#define PAD_RIGHT 0x80
#define OAM_FLIP_V 0x80
#define OAM_FLIP_H 0x40
#define OAM_BEHIND 0x20
#define MAX(x1,x2) ((x1)<(x2)?(x2):(x1))
#define MIN(x1,x2) ((x1)<(x2)?(x1):(x2))
#define MASK_SPR 0x10
#define MASK_BG 0x08
#define MASK_EDGE_SPR 0x04
#define MASK_EDGE_BG 0x02
#define NAMETABLE_A 0x2000
#define NAMETABLE_B 0x2400
#define NAMETABLE_C 0x2800
#define NAMETABLE_D 0x2c00
#define NT_UPD_HORZ 0x40
#define NT_UPD_VERT 0x80
#define NT_UPD_EOF 0xff
// macro to calculate nametable address from X,Y in compile time
#define NTADR_A(x,y) (NAMETABLE_A|(((y)<<5)|(x)))
#define NTADR_B(x,y) (NAMETABLE_B|(((y)<<5)|(x)))
#define NTADR_C(x,y) (NAMETABLE_C|(((y)<<5)|(x)))
#define NTADR_D(x,y) (NAMETABLE_D|(((y)<<5)|(x)))
// macro to get MSB and LSB
#define MSB(x) (((x)>>8))
#define LSB(x) (((x)&0xff))
#pragma compile("neslib.c")
#endif
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "stddef.h"
namespace std
{
void * operator new(size_t size);
void * operator new(void * ptr, size_t size);
}
+84
View File
@@ -0,0 +1,84 @@
#ifndef OPP_ALGORITHM_H
#define OPP_ALGORITHM_H
#include "utility.h"
namespace opp {
template<class T, class LT>
void sort(T s, T e)
{
while (s != e)
{
auto p = s;
auto q = s;
q++;
while (q != e)
{
if (LT(*q, *p))
{
swap(*q, *p);
p++;
swap(*q, *p);
}
q++;
}
sort<T, LT>(s, p);
p++;
s = p;
}
}
template<class T, class LF>
void sort(T s, T e, LF lt)
{
while (s != e)
{
auto p = s;
auto q = s;
q++;
while (q != e)
{
if (lt(*q, *p))
{
swap(*q, *p);
p++;
swap(*q, *p);
}
q++;
}
sort(s, p, lt);
p++;
s = p;
}
}
template<class II, class OI>
OI copy(II first, II last, OI result)
{
while (first != last)
{
*result = *first;
++result; ++first;
}
return result;
}
template<class II, class T>
II find (II first, II last, const T& val)
{
while (first != last)
{
if (*first == val) return first;
++first;
}
return last;
}
}
#endif
+122
View File
@@ -0,0 +1,122 @@
#ifndef OPP_ARRAY_H
#define OPP_ARRAY_H
#include <stddef.h>
namespace opp {
template <class T, int n>
class array
{
protected:
T _data[n];
public:
typedef T element_type;
size_t size(void) const
{
return n;
}
size_t max_size(void) const
{
return n;
}
bool empty(void) const
{
return n == 0;
}
const T & at(size_t at) const
{
return _data[at];
}
T & at(size_t at)
{
return _data[at];
}
T & operator[] (size_t at)
{
return _data[at];
}
const T & operator[] (size_t at) const
{
return _data[at];
}
T * begin(void)
{
return _data;
}
const T * begin(void) const
{
return _data;
}
const T * cbegin(void) const
{
return _data;
}
T * end(void)
{
return _data + n;
}
const T * end(void) const
{
return _data + n;
}
const T * cend(void) const
{
return _data + n;
}
T & back(void)
{
return _data[n - 1];
}
const T & back(void) const
{
return _data[n - 1];
}
T & front(void)
{
return _data[0];
}
const T & front(void) const
{
return _data[0];
}
T * data(void)
{
return _data;
}
const T * data(void) const
{
return _data;
}
void fill(const T & t)
{
for(int i=0; i<n; i++)
_data[i] = t;
}
};
}
#endif
+207
View File
@@ -0,0 +1,207 @@
#ifndef OPP_BIDXLIST_H
#ifndef OPP_BIDXLIST_H
template <class T, int n>
class bindexlist
{
public:
char _free;
char _pred[n], _succ[n];
T _data[n];
class iterator
{
public:
bindexlist * _l;
char _i;
iterator(void) : _l(nullptr) {}
iterator(bindexlist * l, char i)
: _l(l), _i(i) {}
iterator(const iterator & li) : _l(li._l), _i(li._i) {}
iterator & operator=(const iterator & li)
{
_l = li._l;
_i = li._i;
return *this;
}
T & operator*()
{
return _l->_data[_i];
}
T * operator->()
{
return _l->_data + _i;
}
iterator & operator++(void)
{
_i = _l->_succ[_i];
return *this;
}
iterator operator++(int)
{
char i = _i;
_i = _l->_succ[_i];
return bindexlist::iterator(_l, i);
}
iterator & operator+=(char n)
{
while (n--)
_i = _l->_succ[_i];
return *this;
}
iterator & operator--(void)
{
_i = _l->_pred[_i];
return *this;
}
iterator operator++(int)
{
char i = _i;
_i = _l->_pred[_i];
return bindexlist::iterator(_l, i);
}
iterator & operator-=(char n)
{
while (n--)
_i = _l->_pred[_i];
return *this;
}
bool operator==(const iterator & li)
{
return _i == li._i;
}
bool operator!=(const iterator & li)
{
return _i != li._i;
}
};
public:
typedef T element_type;
typedef iterator iterator_type;
bindexlist(void)
{
_succ[0] = 0;
_pred[0] = 0;
for(char i=1; i<n; i++)
_succ[i] = i + 1;
_free = 1;
}
~bindexlist(void)
{
}
iterator begin(void)
{
return iterator(this, _succ[0]);
}
iterator end(void)
{
return iterator(this, 0);
}
T & front(void)
{
return _data[_succ[0]];
}
const T & front(void) const
{
return _data[_succ[0]];
}
T & back(void)
{
return _data[_pred[0]];
}
const T & back(void) const
{
return _data[_pred[0]];
}
iterator erase(iterator it)
{
char s = _succ[it._i];
_succ[_pred[it._i]] = _pred[it._i];
_pred[_succ[it._i]] = s;
_succ[it._i] = _free;
_free = it._i;
return iterator(this, s);
}
iterator erase(iterator first, iterator last)
{
char s = _succ[last._i];
_succ[_pred[last._i]] = _pred[first._i];
_pred[_succ[first._i]] = s;
_succ[last._i] = _free;
_free = first._i;
return iterator(this, s);
}
void pop_front(void)
{
char i = _succ[0];
char s = _succ[i];
_pred[s] = 0;
_succ[0] = s;
_succ[i] = _free;
_free = i;
}
void pop_back(void)
{
char i = _pred[0];
char p = _pred[i];
_succ[p] = 0;
_pred[0] = p;
_pred[i] = _free;
_free = i;
}
void push_back(const T & t)
{
char i = _free;
_data[i] = t;
_free = _succ[_free];
_succ[i] = 0;
_pred[i] = _pred[0];
_succ[_pred[0]] = i;
_pred[0] = i;
}
void push_front(const T & t)
{
char i = _free;
_data[i] = t;
_free = _succ[_free];
_succ[i] = 0;
_succ[i] = _succ[0];
_pred[_succ[0]] = i;
_succ[0] = i;
}
};
#endif
+59
View File
@@ -0,0 +1,59 @@
#ifndef OPP_BOUNDINT_H
#define OPP_BOUNDINT_H
namespace opp {
template<int tmin, int tmax>
constexpr auto boundinttype(void)
{
if constexpr (tmin >= 0 && tmax <= 255)
return (char)0;
else if constexpr (tmin >= -128 && tmax <= 127)
return (signed char)0;
else
return (int)0;
}
template<int tmin, int tmax>
class boundint
{
protected:
decltype(boundinttype<tmin, tmax>()) v;
public:
boundint(int i)
: v(i)
{
__assume(i >= tmin && i <= tmax);
}
void operator=(int k)
{
__assume(k >= tmin && k <= tmax);
v = k;
}
void operator+=(int k)
{
k += v;
__assume(k >= tmin && k <= tmax);
v = k;
}
void operator-=(int k)
{
k = v - k;
__assume(k >= tmin && k <= tmax);
v = k;
}
operator int() const
{
int k = v;
__assume(k >= tmin && k <= tmax);
return k;
}
};
}
#endif
+93
View File
@@ -0,0 +1,93 @@
#ifndef OPP_FUNCTIONAL_H
#define OPP_FUNCTIONAL_H
namespace opp
{
template <class F>
class function;
template <class R, class ... P>
class function<R(P...)>
{
private:
struct callif
{
virtual R call(P...) = 0;
virtual ~callif() {}
virtual callif * clone(void) const = 0;
};
template<class CA>
struct callable : callif
{
CA ca;
callable(CA ca_) : ca(ca_) {}
R call(P... p) {return ca(p...);}
callif * clone(void) const
{
return new callable(ca);
}
};
callif * c;
public:
template <class F>
function(F f)
{
c = new callable<F>(f);
}
function(const function & f)
{
c = f.c->clone();
}
function(function && f)
{
c = f.c;
f.c = nullptr;
}
function(void)
{
c = nullptr;
}
function & operator=(const function & f)
{
if (c != f.c)
{
delete c;
c = f.c;
}
return *this;
}
function & operator=(function && f)
{
if (c != f.c)
{
c = f.c;
f.c = nullptr;
}
return *this;
}
~function(void)
{
delete c;
}
R operator()(P ... p) const
{
return c->call(p...);
}
};
}
#endif
+180
View File
@@ -0,0 +1,180 @@
#ifndef HASHMAP_H
#define HASHMAP_H
#include <opp/list.h>
#include <opp/string.h>
namespace opp {
template<class T>
struct Hash
{};
template<>
struct Hash<int> {
unsigned operator()(const int & k)
{
return k;
}
};
template<>
struct Hash<string> {
unsigned operator()(const string & k)
{
const char * cp = k.begin();
if (cp)
{
unsigned hash = 0;
while (*cp)
hash = hash * 17 + *cp++;
return hash;
}
else
return 0;
}
};
template <class K, class T>
struct hashpair
{
K key;
T value;
unsigned hash;
hashpair(void) {}
hashpair(const K & k, unsigned h) : key(k), hash(h) {}
hashpair(const hashpair<K, T> & p)
: key(p.key), value(p.value), hash(p.hash) {}
};
template<class K, class T>
class hashmap
{
public:
hashmap(void);
~hashmap(void);
typedef hashpair<K, T> N;
typedef list_iterator<N> I;
T & at(const K & key);
void insert(const K & key, const T & value);
void erase(const K & key);
list_iterator<hashpair<K, T> > erase(list_iterator<hashpair<K, T> > iter);
I begin(void);
I end(void);
I find(const K & key);
private:
unsigned mapsize;
unsigned size;
list<N> list;
I * map;
};
template<class K, class T>
hashmap<K, T>::hashmap(void)
: mapsize(0), size(0), map(nullptr)
{}
template<class K, class T>
hashmap<K, T>::~hashmap(void)
{
delete[] map;
}
template<class K, class T>
hashmap<K, T>::I hashmap<K, T>::begin(void)
{
return list.begin();
}
template<class K, class T>
hashmap<K, T>::I hashmap<K, T>::end(void)
{
return list.end();
}
template<class K, class T>
T & hashmap<K, T>::at(const K & key)
{
if (mapsize == 0)
{
mapsize = 16;
map = new I[16];
for(unsigned i=0; i<16; i++)
map[i] = list.end();
}
unsigned m = mapsize - 1;
unsigned h = Hash<K>()(key);
unsigned hi = h & m;
I p = map[hi];
while (p != list.end() && (p->hash & m) == hi)
{
if (p->key == key) return p->value;
p++;
}
p = list.insert(map[hi], N(key, h));
map[hi] = p;
return p->value;
}
template<class K, class T>
hashmap<K, T>::I hashmap<K, T>::find(const K & key)
{
if (mapsize)
{
unsigned m = mapsize - 1;
unsigned h = Hash<K>()(key);
unsigned hi = h & m;
I p = map[hi];
while (p != list.end() && (p->hash & m) == hi)
{
if (p->key == key) return p;
p++;
}
}
return list.end();
}
template<class K, class T>
void hashmap<K, T>::insert(const K & key, const T & value)
{
this->at(key) = value;
}
template<class K, class T>
void hashmap<K, T>::erase(const K & key)
{
erase(find(key));
}
template<class K, class T>
list_iterator<hashpair<K, T> > hashmap<K, T>::erase(list_iterator<hashpair<K, T> > iter)
{
if (iter != list.end())
{
unsigned hi = iter->hash & (mapsize - 1);
bool first = iter == map[hi];
iter = list.erase(iter);
if (first)
map[hi] = iter;
}
return iter;
}
}
#endif
+24
View File
@@ -0,0 +1,24 @@
#include "ifstream.h"
#include <c64/kernalio.h>
namespace opp {
ifstream::ifstream(char fnum, char device, char channel, const string & name)
{
this->fnum = fnum;
krnio_setnam(name.tocstr());
krnio_open(fnum, device, channel);
}
ifstream::~ifstream(void)
{
krnio_close(fnum);
}
void ifstream::refill(void)
{
mBufferPos = 0;
mBufferFill = krnio_read(fnum, mBuffer, 32);
}
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef OPP_IFSTREAM_H
#define OPP_IFSTREAM_H
#include "iostream.h"
#include "string.h"
namespace opp {
class ifstream : public istream
{
public:
ifstream(char fnum, char device, char channel, const string & name);
~ifstream(void);
protected:
virtual void refill(void);
char fnum;
};
}
#pragma compile("ifstream.cpp")
#endif
File diff suppressed because it is too large Load Diff
+217
View File
@@ -0,0 +1,217 @@
#ifndef OPP_IOSTREAM_H
#define OPP_IOSTREAM_H
#include <opp/string.h>
namespace opp {
class ios
{
public:
constexpr ios(void);
virtual ~ios(void);
char fill() const;
char fill(char cillch);
char width() const;
char width(char wide);
char precision() const;
char precision(char prec);
enum fmtflags
{
boolalpha = 0x0001,
dec = 0x0002,
fixed = 0x0004,
hex = 0x0008,
internal = 0x0010,
left = 0x0020,
oct = 0x0040,
right = 0x0080,
scientific = 0x0100,
showbase = 0x0200,
showpoint = 0x0400,
showpos = 0x0800,
skipws = 0x1000,
unitbuf = 0x2000,
uppercase = 0x4000,
adjustfield = 0x00b0,
basefield = 0x004a,
floatfield = 0x0104
};
enum statebits
{
goodbit = 0,
badbit = 1,
eofbit = 2,
failbit = 4,
};
fmtflags flags(void) const;
fmtflags flags(fmtflags f);
fmtflags setf(fmtflags f);
fmtflags setf(fmtflags f, fmtflags m);
fmtflags unsetf(fmtflags f);
bool good(void) const;
bool eof(void) const;
bool fail(void) const;
bool bad(void) const;
bool operator!(void) const;
operator bool(void);
statebits rdstate(void) const;
void clear(void);
protected:
fmtflags mFlags;
statebits mState;
char mWidth;
char mPrecision;
char mFill;
};
class ostream;
typedef ostream & (* manip)(ostream &);
class ostream : public ios
{
public:
constexpr ostream(void);
ostream & put(char c);
ostream & write(const char * s, int n);
ostream & operator<<(bool val);
ostream & operator<<(char val);
ostream & operator<<(int val);
ostream & operator<<(unsigned val);
ostream & operator<<(long val);
ostream & operator<<(unsigned long val);
ostream & operator<<(float val);
ostream & operator<<(const char * p);
ostream & operator<<(const string & s);
ostream & operator<<(manip m);
protected:
void putnum(const char * buffer, char prefix, char size);
void numput(unsigned n, char sign);
void numput(unsigned long n, char sign);
virtual void bput(char ch);
};
class istream : public ios
{
public:
char get(void);
istream & get(char & c);
istream & get(char * s, char size);
istream & get(char * s, char size, char delim);
istream & getline(char * s, char size);
istream & getline(char * s, char size, char delim);
istream & ignore(char size);
istream & ignore(char size, char delim);
istream & putback(char c);
istream & unget(void);
istream & operator>>(char & val);
istream & operator>>(bool & val);
istream & operator>>(int & val);
istream & operator>>(unsigned & val);
istream & operator>>(long & val);
istream & operator>>(unsigned long & val);
istream & operator>>(float & val);
istream & operator>>(char * p);
istream & operator>>(string & s);
istream(void);
protected:
char mBuffer[32];
char mBufferPos, mBufferFill;
virtual void refill(void);
unsigned getnum(void);
unsigned long getnuml(void);
float getnumf(void);
void doskipws(void);
};
class costream : public ostream
{
public:
constexpr costream(void);
protected:
void bput(char ch);
};
class cistream : public istream
{
public:
cistream(void);
protected:
void refill(void);
};
ostream & endl(ostream & os);
struct iosetf {
ios::fmtflags flags;
iosetf(ios::fmtflags flags_) : flags(flags_) {}
};
ostream & operator<<(ostream & os, const iosetf & s);
iosetf setf(ios::fmtflags flags);
struct iosetw {
char width;
iosetw(char width_) : width(width_) {}
};
iosetw setw(char width);
ostream & operator<<(ostream & os, const iosetw & s);
struct iosetprecision {
char precision;
iosetprecision(char precision_) : precision(precision_) {}
};
iosetprecision setprecision(char precision);
ostream & operator<<(ostream & os, const iosetprecision & s);
struct iosetfill {
char fill;
iosetfill(char fill_) : fill(fill_) {}
};
iosetfill setfill(char fill);
ostream & operator<<(ostream & os, const iosetfill & s);
extern cistream cin;
extern costream cout;
}
#pragma compile("iostream.cpp");
#endif
+201
View File
@@ -0,0 +1,201 @@
#ifndef OPP_ITERATOR_H
#define OPP_ITERATOR_H
namespace opp
{
template <class CT>
class back_insert_iterator
{
protected:
CT * co;
public:
back_insert_iterator (CT & c) : co(&c) {}
back_insert_iterator & operator= (const CT::element_type & t)
{
co->push_back(t);
return *this;
}
back_insert_iterator & operator= (CT::element_type && t)
{
co->push_back(t);
return *this;
}
back_insert_iterator & operator* (void)
{
return *this;
}
back_insert_iterator & operator++ (void)
{
return *this;
}
back_insert_iterator operator++ (int)
{
return *this;
}
};
template <class CT>
class front_insert_iterator
{
protected:
CT * co;
public:
front_insert_iterator (CT & c) : co(&c) {}
front_insert_iterator & operator= (const CT::element_type & t)
{
co->push_front(t);
return *this;
}
front_insert_iterator & operator= (CT::element_type && t)
{
co->push_front(t);
return *this;
}
front_insert_iterator & operator* (void)
{
return *this;
}
front_insert_iterator & operator++ (void)
{
return *this;
}
front_insert_iterator operator++ (int)
{
return *this;
}
};
template <class CT>
class insert_iterator
{
protected:
CT * co;
CT::iterator_type ci;
public:
insert_iterator (CT & c, const CT::iterator_type & i) : co(&c), ci(i) {}
insert_iterator & operator= (const CT::element_type & t)
{
ci = co->insert(ci, t); ++ci;
return *this;
}
insert_iterator & operator= (CT::element_type && t)
{
ci = co->insert(ci, t); ++ci;
return *this;
}
insert_iterator & operator* (void)
{
return *this;
}
insert_iterator & operator++ (void)
{
return *this;
}
insert_iterator operator++ (int)
{
return *this;
}
};
template <class T>
class ostream_iterator
{
protected:
ostream & stream;
const char * str;
public:
ostream_iterator(ostream & stream_, const char * str_)
: stream(stream_), str(str_) {}
ostream_iterator & operator= (const T & t)
{
stream << t;
if (str)
stream << str;
return *this;
}
ostream_iterator & operator= (T && t)
{
stream << t;
if (str)
stream << str;
return *this;
}
ostream_iterator & operator* (void)
{
return *this;
}
ostream_iterator & operator++ (void)
{
return *this;
}
ostream_iterator operator++ (int)
{
return *this;
}
};
template <class CT>
front_insert_iterator<CT> front_inserter (CT & c)
{
return front_insert_iterator<CT>(c);
}
template <class CT>
back_insert_iterator<CT> back_inserter (CT & c)
{
return back_insert_iterator<CT>(c);
}
template <class CT>
insert_iterator<CT> inserter (CT & c, const CT::iterator_type & i)
{
return insert_iterator<CT>(c, i);
}
template <class CT>
CT next(CT it, int n = 1)
{
while (n > 0)
{
it++;
n--;
}
return it;
}
template <class CT>
CT prev(CT it, int n = 1)
{
while (n > 0)
{
it--;
n--;
}
return it;
}
}
+370
View File
@@ -0,0 +1,370 @@
#ifndef OPP_LIST
#define OPP_LIST
namespace opp
{
template <class T>
class listhead
{
public:
listnode<T> * succ, * pred;
listhead()
{
succ = (listnode<T> *)this;
pred = (listnode<T> *)this;
}
};
template <class T>
class listnode : public listhead<T>
{
public:
T data;
listnode(const T & t) : data(t) {}
listnode(T && t) : data(t) {}
};
template <class T>
class list_iterator
{
public:
listnode<T> * node;
public:
list_iterator(void) : node(nullptr) {}
list_iterator(listnode<T> * n) : node(n) {}
list_iterator(const list_iterator & li) : node(li.node) {}
list_iterator & operator=(const list_iterator & li)
{
node = li.node;
return *this;
}
T & operator*()
{
return node->data;
}
T * operator->()
{
return &(node->data);
}
list_iterator & operator++(void)
{
node = node->succ;
return *this;
}
list_iterator operator++(int)
{
listnode<T> * n = node;
node = node->succ;
return list_iterator(n);
}
list_iterator & operator+=(int n)
{
while (n--)
node = node->succ;
return *this;
}
list_iterator & operator--(void)
{
node = node->pred;
return *this;
}
list_iterator operator++(int)
{
listnode<T> * n = node;
node = node->pred;
return list_iterator(n);
}
list_iterator & operator-=(int n)
{
while (n--)
node = node->pred;
return *this;
}
bool operator==(const list_iterator & li)
{
return node == li.node;
}
bool operator!=(const list_iterator & li)
{
return node != li.node;
}
};
template <class T>
class list
{
private:
typedef listnode<T> ln;
listhead<T> head;
public:
typedef T element_type;
typedef list_iterator<T> iterator_type;
list(void)
{}
list(const list & l);
list(list && l)
{
head.succ = l.head.succ;
head.pred = l.head.pred;
head.succ->pred = (listnode<T> *)&head;
head.pred->succ = (listnode<T> *)&head;
l.head.succ = (listnode<T> *)&(l.head);
l.head.pred = (listnode<T> *)&(l.head);
}
list & operator=(const list & l);
list & operator=(list && l)
{
head.succ = l.head.succ;
head.pred = l.head.pred;
head.succ->pred = (listnode<T> *)&head;
head.pred->succ = (listnode<T> *)&head;
l.head.succ = (listnode<T> *)&(l.head);
l.head.pred = (listnode<T> *)&(l.head);
return *this;
}
~list(void)
{
listnode<T> * n = head.succ;
while (n != &head)
{
listnode<T> * m = n->succ;
delete n;
n = m;
}
}
list_iterator<T> begin(void)
{
return list_iterator<T>(head.succ);
}
list_iterator<T> end(void)
{
return list_iterator<T>((listnode<T> *)&head);
}
T & front(void)
{
return head.succ->data;
}
const T & front(void) const
{
return head.succ->data;
}
T & back(void)
{
return head.pred->data;
}
const T & back(void) const
{
return head.pred->data;
}
list_iterator<T> erase(list_iterator<T> it);
list_iterator<T> erase(list_iterator<T> first, list_iterator<T> last);
void pop_front(void);
void pop_back(void);
void push_front(const T & t);
void push_front(T && t);
void push_back(const T & t);
void push_back(T && t);
void clear(void);
void append(const list & l);
list_iterator<T> insert(list_iterator<T> it, const T & t);
list_iterator<T> insert(list_iterator<T> it, T && t);
};
template <class T>
list<T>::list(const list<T> & l)
{
append(l);
}
template <class T>
list<T> & list<T>::operator=(const list<T> & l)
{
if (&l != this)
{
clear();
append(l);
}
return *this;
}
template <class T>
void list<T>::pop_front(void)
{
listnode<T> * n = head.succ;
head.succ = n->succ;
n->succ->pred = (listnode<T> *)&head;
delete n;
}
template <class T>
void list<T>::pop_back(void)
{
listnode<T> * n = head.pred;
head.pred = n->pred;
n->pred->succ = (listnode<T> *)&head;
delete n;
}
template <class T>
void list<T>::push_front(const T & t)
{
listnode<T> * n = new listnode<T>(t);
n->pred = (listnode<T> *)&head;
n->succ = head.succ;
head.succ->pred = n;
head.succ = n;
}
template <class T>
void list<T>::push_front(T && t)
{
listnode<T> * n = new listnode<T>(t);
n->pred = (listnode<T> *)&head;
n->succ = head.succ;
head.succ->pred = n;
head.succ = n;
}
template <class T>
void list<T>::push_back(const T & t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = (listnode<T> *)&head;
n->pred = head.pred;
head.pred->succ = n;
head.pred = n;
}
template <class T>
void list<T>::push_back(T && t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = (listnode<T> *)&head;
n->pred = head.pred;
head.pred->succ = n;
head.pred = n;
}
template <class T>
list_iterator<T> list<T>::erase(list_iterator<T> it)
{
listnode<T> * n = it.node;
listnode<T> * s = n->succ;
n->succ->pred = n->pred;
n->pred->succ = n->succ;
delete n;
return list_iterator<T>(s);
}
template <class T>
list_iterator<T> list<T>::erase(list_iterator<T> first, list_iterator<T> last)
{
listnode<T> * n = first.node;
listnode<T> * s = last.node;
n->pred->succ = s;
s->pred = n->pred;
while (n != s)
{
listnode<T> * m = n->succ;
delete n;
n = m;
}
return list_iterator<T>(s);
}
template <class T>
list_iterator<T> list<T>::insert(list_iterator<T> it, const T & t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = it.node;
n->pred = it.node->pred;
it.node->pred->succ = n;
it.node->pred = n;
return list_iterator<T>(n);
}
template <class T>
list_iterator<T> list<T>::insert(list_iterator<T> it, T && t)
{
listnode<T> * n = new listnode<T>(t);
n->succ = it.node;
n->pred = it.node->pred;
it.node->pred->succ = n;
it.node->pred = n;
return list_iterator<T>(n);
}
template <class T>
void list<T>::clear(void)
{
listnode<T> * n = head.succ;
while (n != &head)
{
listnode<T> * m = n->succ;
delete n;
n = m;
}
head.succ = (listnode<T> *)&head;
head.pred = (listnode<T> *)&head;
}
template <class T>
void list<T>::append(const list<T> & l)
{
listnode<T> * n = l.head.succ;
while (n != &(l.head))
{
push_back(n->data);
n = n->succ;
}
}
}
#endif
+122
View File
@@ -0,0 +1,122 @@
#ifndef OPP_NUMERIC_H
#define OPP_NUMERIC_H
namespace opp {
template<class InputIt, class T>
constexpr T accumulate( InputIt first, InputIt last, T init)
{
for (; first != last; ++first)
init = opp::move(init) + *first;
return init;
}
template<class InputIt, class T, class BinaryOperator>
constexpr T accumulate( InputIt first, InputIt last, T init, BinaryOperator op)
{
for (; first != last; ++first)
init = op(opp::move(init), *first);
return init;
}
template<class ForwardIt, class T>
constexpr void iota(ForwardIt first, ForwardIt last, T value)
{
for (; first != last; ++first, ++value)
*first = value;
}
template<class InputIt1, class InputIt2, class T>
constexpr T inner_product(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init)
{
while (first1 != last1)
{
init = opp::move(init) + (*first1) * (*first2);
++first1;
++first2;
}
return init;
}
template<class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2>
constexpr T inner_product(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOp1 op1, BinaryOp2 op2)
{
while (first1 != last1)
{
init = op1(opp::move(init), op2(*first1, *first2));
++first1;
++first2;
}
return init;
}
template< class InputIt, class OutputIt, class T >
OutputIt exclusive_scan( InputIt first, InputIt last, OutputIt d_first, T init )
{
while (first != last)
{
*d_first = init;
init = opp::move(init) + *first;
++d_first;
++first;
}
return d_first;
}
template< class InputIt, class OutputIt >
OutputIt inclusive_scan( InputIt first, InputIt last, OutputIt d_first )
{
if (first == last)
return d_first;
auto sum = *first;
*d_first = sum;
while (++first != last)
{
sum = opp::move(sum) + *first;
*++d_first = sum;
}
return ++d_first;
}
template< class InputIt, class OutputIt, class T, class BinaryOperator >
OutputIt exclusive_scan( InputIt first, InputIt last, OutputIt d_first, T init, BinaryOperator op )
{
while (first != last)
{
*d_first = init;
init = op(opp::move(init), *first);
++d_first;
++first;
}
return d_first;
}
template< class InputIt, class OutputIt, class BinaryOperator >
OutputIt inclusive_scan( InputIt first, InputIt last, OutputIt d_first, BinaryOperator op )
{
if (first == last)
return d_first;
auto sum = *first;
*d_first = sum;
while (++first != last)
{
sum = op(opp::move(sum), *first);
*++d_first = sum;
}
return ++d_first;
}
}
#endif
+32
View File
@@ -0,0 +1,32 @@
#include "ofstream.h"
#include <c64/kernalio.h>
namespace opp {
ofstream::ofstream(char fnum, char device, char channel, const string & name)
{
this->fnum = fnum;
krnio_setnam(name.tocstr());
krnio_open(fnum, device, channel);
mBufferFill = 0;
}
ofstream::~ofstream(void)
{
if (mBufferFill > 0)
krnio_write(fnum, mBuffer, mBufferFill);
krnio_close(fnum);
}
void ofstream::bput(char ch)
{
mBuffer[mBufferFill++] = ch;
if (mBufferFill == 32)
{
krnio_write(fnum, mBuffer, mBufferFill);
mBufferFill = 0;
}
}
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef OPP_OFSTREAM_H
#define OPP_OFSTREAM_H
#include "iostream.h"
#include "string.h"
namespace opp {
class ofstream : public ostream
{
public:
ofstream(char fnum, char device, char channel, const string & name);
~ofstream(void);
protected:
virtual void bput(char ch);
char mBuffer[32];
char mBufferFill;
char fnum;
};
}
#pragma compile("ofstream.cpp")
#endif
+112
View File
@@ -0,0 +1,112 @@
#ifndef OPP_OPTIONAL_H
#define OPP_OPTIONAL_H
#include <opp/utility.h>
namespace opp {
template <class T>
class optional
{
protected:
char _data[sizeof(T)];
bool valid;
public:
optional(void) : valid(false) {}
optional(const T & data) : valid(true)
{
new (_data)T(data);
}
optional(T && data) : valid(true)
{
new (_data)T(opp::move(data));
}
optional(const optional<T> & o)
: valid(o.valid)
{
if (valid)
new (_data)T(*((T*)o._data));
}
optional(optional<T> && o)
: valid(o.valid)
{
if (valid)
new (_data)T(opp::move(*((T*)o._data)));
}
~optional(void)
{
if (valid)
((T*)_data)->~T();
}
optional<T> & operator=(const optional<T> & o)
{
if (this != &o)
{
if (valid)
((T*)_data)->~T();
valid = o.valid;
if (valid)
new (_data)T(*((T*)o._data));
}
return *this;
}
optional<T> & operator=(optional<T> && o)
{
if (this != &o)
{
if (valid)
((T*)_data)->~T();
valid = o.valid;
if (valid)
new (_data)T(opp::move(*((T*)o._data)));
}
return *this;
}
operator bool(void) const {return valid;}
T & operator *(void) const {return *(T*)_data;}
const T & operator *(void) const {return *(T*)_data;}
const T * operator->(void) const {return (T*)_data;}
T * begin(void)
{
return (T*)_data;
}
const T * begin(void) const
{
return (T*)_data;
}
const T * cbegin(void) const
{
return (T*)_data;
}
T * end(void)
{
return (T*)_data + (valid ? 1 : 0);
}
const T * end(void) const
{
return (T*)_data + (valid ? 1 : 0);
}
const T * cend(void) const
{
return (T*)_data + (valid ? 1 : 0);
}
};
}
#endif
+80
View File
@@ -0,0 +1,80 @@
#ifndef OPP_SLAB_H
#define OPP_SLAB_H
template<class T, int N>
class slabptr
{
public:
char index;
slabptr(void)
: index(N)
{}
slabptr(char i)
: index(i)
{}
slabptr(const slabptr & i)
: index(i.index)
{}
auto operator-> ();
auto & operator* ();
};
template <class T, int N>
class slab
{
protected:
static __striped T buffer[N];
static char head;
static char next[N];
public:
typedef slabptr<T, N> ptr;
static void init(void);
static auto alloc(void);
static void free(ptr p);
};
template<class T, int N>
inline auto slabptr<T, N>::operator-> ()
{
return slab<T, N>::buffer + index;
}
template<class T, int N>
inline auto & slabptr<T, N>::operator* ()
{
return slab<T, N>::buffer[index];
}
template <class T, int N>
void slab<T, N>::init(void)
{
head = 0;
for(char i=0; i<N; i++)
next[i] = i + 1;
}
template <class T, int N>
auto slab<T, N>::alloc(void)
{
char i = head;
head = next[head];
return slabptr<T, N>(i);
}
template <class T, int N>
void slab<T, N>::free(slabptr<T, N> p)
{
next[p.index] = head;
head = p.index;
}
#endif
+169
View File
@@ -0,0 +1,169 @@
#ifndef OPP_SPAN_H
#define OPP_SPAN_H
#include <stddef.h>
#include <stdlib.h>
#include <opp/utility.h>
namespace opp
{
static const size_t dynamic_extent = 0xffff;
template <class T, int N = dynamic_extent>
class span
{
protected:
T * _data;
size_t _size;
public:
span(void)
: _data(nullptr), _size(0)
{}
span(T * data, size_t size)
: _data(data), _size(size)
{}
span(T * data)
: _data(data), _size(N)
{}
span(opp::array<T, N> & arr)
: _data(arr.data()), _size(N)
{}
span(opp::vector<T> & vec)
: _data(vec.data()), _size(vec.size())
{}
span(const opp::array<T, N> & arr)
: _data(arr.data()), _size(N)
{}
span(const opp::vector<T> & vec)
: _data(vec.data()), _size(vec.size())
{}
constexpr size_t size(void) const
{
if constexpr (N == dynamic_extent)
return _size;
else
return N;
}
T & operator[](int i)
{return _data[i];}
const T & operator[](int i) const
{return _data[i];}
T * begin(void)
{
return _data;
}
const T * begin(void) const
{
return _data;
}
const T * cbegin(void) const
{
return _data;
}
T * end(void)
{
return _data + size();
}
const T * end(void) const
{
return _data + size();
}
const T * cend(void) const
{
return _data + size();
}
T & back(void)
{
return _data[size() - 1];
}
const T & back(void) const
{
return _data[size() - 1];
}
T & front(void)
{
return _data[0];
}
const T & front(void) const
{
return _data[0];
}
T * data(void)
{
return _data;
}
const T * data(void) const
{
return _data;
}
template< int Offset, int Count = dynamic_extent >
constexpr auto subspan() const
{
if constexpr (Count == dynamic_extent)
{
if constexpr (N == dynamic_extent)
return opp::span<T>(_data + Offset, _size - Offset);
else
return opp::span<T, (N - Offset)>(_data + Offset);
}
else
return opp::span<T, Count>(_data + Offset);
}
constexpr auto subspan(size_t offset, size_t count = dynamic_extent)
{
if (count == dynamic_extent)
return opp::span<T>(_data + offset, size() - offset);
else
return opp::span<T>(_data + offset, count);
}
template< int Count >
constexpr auto first() const
{
return opp::span<T, Count>(_data);
}
constexpr auto first( size_t count ) const
{
return opp::span<T>(_data, count);
}
template< int Count >
constexpr auto last() const
{
return opp::span<T, Count>(_data + size() - Count);
}
constexpr auto last( size_t count ) const
{
return opp::span<T>(_data + size() - count, count);
}
};
}
#endif
+86
View File
@@ -0,0 +1,86 @@
#include "sstream.h"
#include <stdlib.h>
namespace opp {
ostringstream::ostringstream(void)
{
mBuffer = nullptr;
mBFill = mBSize = 0;
}
ostringstream::~ostringstream(void)
{
free(mBuffer);
}
void ostringstream::bput(char ch)
{
if (!mBuffer)
{
mBSize = 15;
mBFill = 0;
mBuffer = (char *)malloc(15);
}
else if (mBFill == mBSize)
{
mBSize *= 2;
char * b = (char *)malloc(mBSize);
for(char i=0; i<mBFill; i++)
b[i] = mBuffer[i];
free(mBuffer);
mBuffer = b;
}
mBuffer[mBFill++] = ch;
}
string ostringstream::str(void) const
{
return string(mBuffer, mBFill);
}
void ostringstream::str(const string & str)
{
mBFill = str.size();
if (mBFill > mBSize)
{
free(mBuffer);
mBSize = mBFill;
mBuffer = (char *)malloc(mBSize);
}
str.copyseg(mBuffer, 0, mBFill);
}
istringstream::istringstream(const string & str)
: mString(str), mSPos(0)
{}
istringstream::~istringstream(void)
{}
string istringstream::str(void) const
{
return mString;
}
void istringstream::str(const string & str)
{
mState = goodbit;
mString = str;
mSPos = 0;
}
void istringstream::refill(void)
{
mBufferFill = 0;
mBufferPos = 0;
char ch;
while (mSPos < mString.size() && mBufferFill < 32)
{
mBuffer[mBufferFill++] = mString[mSPos++];
}
}
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef OPP_SSTREAM_H
#define OPP_SSTREAM_H
#include "iostream.h"
namespace opp {
class ostringstream : public ostream
{
public:
ostringstream(void);
~ostringstream(void);
string str(void) const;
void str(const string & str);
protected:
void bput(char ch);
char * mBuffer;
char mBFill, mBSize;
};
class istringstream : public istream
{
public:
istringstream(const string & str);
~istringstream(void);
string str(void) const;
void str(const string & str);
protected:
virtual void refill(void);
string mString;
char mSPos;
};
}
#pragma compile("sstream.cpp")
#endif
+308
View File
@@ -0,0 +1,308 @@
#ifndef OPP_STATIC_VECTOR_H
#define OPP_STATIC_VECTOR_H
#include <new>
#include <stdlib.h>
#include <opp/utility.h>
#include <oscar.h>
namespace opp {
template <class T, int N>
class static_vector
{
protected:
enum { m = N } _size;
char _space[N * sizeof(T)];
public:
typedef T element_type;
static_vector(void) : _size(0) {}
static_vector(size_t n) : _size(n)
{
#ifdef CAPACITYCHECK
if (n > N) debugcrash();
#endif
T * data = (T*)_space;
for(size_t i=0; i<n; i++)
new (data + i) T();
}
static_vector(const static_vector & v)
: _size(v._size)
{
size_t n = _size;
T * data = (T*)_space, * vdata = (T*)(v._space);
for(size_t i=0; i<n; i++)
new (data + i)T(vdata[i]);
}
~static_vector(void)
{
T * data = (T*)_space;
size_t n = _size;
for(size_t i=0; i<n; i++)
data[i].~T();
}
static_vector & operator=(const static_vector & v)
{
if (this != &v)
{
T * data = (T*)_space, * vdata = (T*)(v._space);
size_t n = _size;
for(size_t i=0; i<n; i++)
data[i].~T();
_size = v._size;
n = _size;
for(size_t i=0; i<n; i++)
new (data + i)T(vdata[i]);
}
return *this;
}
size_t size(void) const
{
return _size;
}
size_t max_size(void) const
{
return N;
}
bool empty(void) const
{
return _size == 0;
}
bool full(void) const
{
return _size == N;
}
size_t capacity(void) const
{
return N;
}
void resize(size_t n);
void clear(void);
T & at(size_t at)
{
return ((T*)_space)[at];
}
const T & at(size_t at) const
{
return ((T*)_space)[at];
}
T & operator[](size_t at)
{
return ((T*)_space)[at];
}
const T & operator[](size_t at) const
{
return ((T*)_space)[at];
}
T * begin(void)
{
return (T*)_space;
}
const T * begin(void) const
{
return (T*)_space;
}
const T * cbegin(void) const
{
return (T*)_space;
}
T * end(void)
{
return (T*)_space + _size;
}
const T * end(void) const
{
return (T*)_space + _size;
}
const T * cend(void) const
{
return (T*)_space + _size;
}
T & front(void)
{
return ((T*)_space)[0];
}
const T & front(void) const
{
return ((T*)_space)[0];
}
T & back(void)
{
return ((T*)_space)[_size - 1];
}
const T & back(void) const
{
return ((T*)_space)[_size - 1];
}
T * data(void)
{
return (T*)_space;
}
const T * at(void) const
{
return (T*)_space;
}
void push_back(const T & t);
void push_back(T && t);
void pop_back(void)
{
_size--;
((T*)_space)[_size].~T();
}
void assign(size_t count, const T & t);
void insert(size_t at, const T & t);
void erase(size_t at, size_t n = 1);
T * insert(T * at, const T & t);
template <typename ...P>
void emplace_back(const P&... p);
};
template <class T, int N>
void static_vector<T, N>::clear(void)
{
T * data = (T*)_space;
for(size_t i=0; i<_size; i++)
data[i].~T();
_size = 0;
}
template <class T, int N>
void static_vector<T, N>::resize(size_t n)
{
#ifdef CAPACITYCHECK
if (n > N) debugcrash();
#endif
T * data = (T*)_space;
if (n < _size)
{
for(size_t i=n; i<_size; i++)
data[i].~T();
}
else if (n > 0)
{
for(size_t i=_size; i<n; i++)
new(data + i)T();
}
_size = n;
}
template <class T, int N>
void static_vector<T, N>::push_back(const T & t)
{
#ifdef CAPACITYCHECK
if (_size >= N) debugcrash();
#endif
new ((T*)_space + _size++)T(t);
}
template <class T, int N>
void static_vector<T, N>::push_back(T && t)
{
#ifdef CAPACITYCHECK
if (_size >= N) debugcrash();
#endif
new ((T*)_space + _size++)T(t);
}
template <class T, int N>
template <typename ...P>
void static_vector<T, N>::emplace_back(const P&... p)
{
#ifdef CAPACITYCHECK
if (_size >= N) debugcrash();
#endif
new ((T*)_space + _size++)T(p...);
}
template <class T, int N>
void static_vector<T, N>::assign(size_t count, const T & t)
{
T * data = (T*)_space;
for(size_t i=0; i<_size; i++)
data[i].~T();
for(size_t i=0; i<count; i++)
new (data + i)T(t);
_size = count;
}
template <class T, int N>
void static_vector<T, N>::insert(size_t at, const T & t)
{
T * data = (T*)_space;
new (data + _size)T();
for(size_t i=_size; i>at; i--)
data[i] = move(data[i - 1]);
data[at] = t;
_size++;
}
template <class T, int N>
void static_vector<T, N>::erase(size_t at, size_t n)
{
T * data = (T*)_space;
_size -= n;
for(size_t i=at; i<_size; i++)
data[i] = move(data[i + n]);
for(size_t i=0; i<n; i++)
data[_size + i].~T();
}
template <class T, int N>
T * static_vector<T, N>::insert(T * at, const T & t)
{
#ifdef CAPACITYCHECK
if (_size >= N) debugcrash();
#endif
T * data = (T*)_space;
T * dp = data + _size;
new (dp)T();
while (dp != at)
{
dp--;
dp[1] = move(dp[0]);
}
dp[0] = t;
_size++;
return dp + 1;
}
}
#endif
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
#ifndef OPP_STRING_H
#define OPP_STRING_H
namespace opp {
class string
{
private:
char * cstr;
friend void swap(string & u, string & v);
public:
string(void);
string(const string & s);
string(string && s);
string(const char * s);
string(const char * s, char size);
string(char c);
~string(void);
unsigned size(void) const;
void clear(void);
string & operator=(const string & s);
string & operator=(string && s);
string & operator=(const char * s);
string & operator+=(const string & s);
string & operator+=(const char * s);
string & operator+=(char c);
string operator+(const string & s) const;
string operator+(const char * s) const;
string operator+(char c) const;
string & operator<<=(char n);
string & operator>>=(char n);
string operator<<(char n) const;
string operator>>(char n) const;
bool operator==(const string & s) const;
bool operator==(const char * s) const;
bool operator!=(const string & s) const;
bool operator!=(const char * s) const;
bool operator<(const string & s) const;
bool operator<(const char * s) const;
bool operator<=(const string & s) const;
bool operator<=(const char * s) const;
bool operator>(const string & s) const;
bool operator>(const char * s) const;
bool operator>=(const string & s) const;
bool operator>=(const char * s) const;
char & operator[](char t);
char operator[](char t) const;
char * begin(void);
const char * begin(void) const;
const char * cbegin(void) const;
char * end(void);
const char * end(void) const;
const char * cend(void) const;
const char * c_str(void) const;
const char * tocstr(void) const;
string substr(char pos, char len) const;
int find(const string & s) const;
int find(const char * s) const;
int find(char c) const;
int find(const string & s, char pos) const;
int find(const char * s, char pos) const;
int find(char c, char pos) const;
void copyseg(char * p, char at, char num) const;
int to_int(char * idx = nullptr, char base = 10) const;
long to_long(char * idx = nullptr, char base = 10) const;
unsigned to_uint(char * idx = nullptr, char base = 10) const;
unsigned long to_ulong(char * idx = nullptr, char base = 10) const;
float to_float(char * idx = nullptr) const;
protected:
string(char l, char * b);
};
void swap(string & u, string & v);
string to_string(int val);
string to_string(long val);
string to_string(unsigned int val);
string to_string(unsigned long val);
string to_string(float val);
}
#pragma compile("string.cpp")
#endif
+40
View File
@@ -0,0 +1,40 @@
#ifndef OPP_UTILITY_H
#define OPP_UTILITY_H
namespace opp {
template <class T>
inline T && move(T && m)
{
return (T &&)m;
}
template <class T>
inline void swap(T & x, T & y)
{
T t(x); x = y; y = move(t);
}
template<class T1, class T2>
struct pair
{
T1 first;
T2 second;
pair(T1 && t1, T2 && t2)
: first(t1), second(t2)
{}
};
template<class T1, class T2>
constexpr pair<T1, T2> make_pair(T1 && t1, T2 && t2)
{
return pair<T1, T2>(t1, t2);
}
}
#endif
+364
View File
@@ -0,0 +1,364 @@
#ifndef OPP_VECTOR_H
#define OPP_VECTOR_H
#include <new>
#include <stdlib.h>
#include <opp/utility.h>
namespace opp {
template <class T>
class vector
{
protected:
T * _data;
size_t _size, _capacity;
public:
typedef T element_type;
vector(void) : _data(nullptr), _size(0), _capacity(0) {}
vector(size_t n) : _data((T*)malloc(n * sizeof(T))), _size(n), _capacity(n)
{
for(size_t i=0; i<n; i++)
new (_data + i) T();
}
vector(const vector & v)
: _data((T*)malloc(v._size * sizeof(T))), _size(v._size), _capacity(v._size)
{
size_t n = _size;
for(size_t i=0; i<n; i++)
new (_data + i)T(v._data[i]);
}
vector(vector && v)
: _data(v._data), _size(v._size), _capacity(v._capacity)
{
v._data = nullptr;
v._size = 0;
v._capacity = 0;
}
~vector(void)
{
for(size_t i=0; i<_size; i++)
_data[i].~T();
free(_data);
}
vector & operator=(const vector & v)
{
if (this != &v)
{
size_t n = _size;
for(size_t i=0; i<n; i++)
_data[i].~T();
free(_data);
_data = (T*)malloc(v._size * sizeof(T));
_size = v._size;
_capacity = v._size;
n = _size;
for(size_t i=0; i<n; i++)
new (_data + i)T(v._data[i]);
}
return *this;
}
vector & operator=(vector && v)
{
if (this != &v)
{
swap(_data, v._data);
swap(_size, v._size);
swap(_capacity, v._capacity);
}
return *this;
}
size_t size(void) const
{
return _size;
}
size_t max_size(void) const
{
return 32767;
}
bool empty(void) const
{
return _size == 0;
}
size_t capacity(void) const
{
return _capacity;
}
void clear(void);
void resize(size_t n);
void reserve(size_t n);
void shrink_to_fit(void);
T & at(size_t at)
{
return _data[at];
}
const T & at(size_t at) const
{
return _data[at];
}
T & operator[](size_t at)
{
return _data[at];
}
const T & operator[](size_t at) const
{
return _data[at];
}
T * begin(void)
{
return _data;
}
const T * begin(void) const
{
return _data;
}
const T * cbegin(void) const
{
return _data;
}
T * end(void)
{
return _data + _size;
}
const T * end(void) const
{
return _data + _size;
}
const T * cend(void) const
{
return _data + _size;
}
T & front(void)
{
return _data[0];
}
const T & front(void) const
{
return _data[0];
}
T & back(void)
{
return _data[_size - 1];
}
const T & back(void) const
{
return _data[_size - 1];
}
T * data(void)
{
return _data;
}
const T * at(void) const
{
return _data;
}
void push_back(const T & t);
void push_back(T && t);
void pop_back(void)
{
_size--;
_data[_size].~T();
}
void assign(size_t count, const T & t);
void insert(size_t at, const T & t);
void erase(size_t at, size_t n = 1);
T * insert(T * at, const T & t);
template <typename ...P>
void emplace_back(const P&... p);
protected:
T * add_back(void);
};
template <class T>
__noinline void vector<T>::reserve(size_t n)
{
if (n > _capacity)
{
_capacity = n;
T * d = (T *)malloc(_capacity * sizeof(T));
size_t s = _size;
for(size_t i=0; i<s; i++)
{
new (d + i)T(move(_data[i]));
_data[i].~T();
}
free(_data);
_data = d;
}
}
template <class T>
void vector<T>::clear(void)
{
for(size_t i=0; i<_size; i++)
_data[i].~T();
_size = 0;
}
template <class T>
__noinline void vector<T>::resize(size_t n)
{
if (n < _size)
{
for(size_t i=n; i<_size; i++)
_data[i].~T();
_size = n;
}
else if (n < _capacity)
{
for(size_t i=_size; i<n; i++)
new(_data + i)T();
_size = n;
}
else
{
reserve(n);
_size = n;
}
}
template <class T>
void vector<T>::shrink_to_fit(void)
{
if (_size < _capacity)
{
_capacity = _size;
T * d = (T *)malloc(_capacity * sizeof(T));
for(size_t i=0; i<_size; i++)
{
new (d + i)T(move(_data[i]));
_data[i].~T();
}
free(_data);
_data = d;
}
}
template <class T>
T * vector<T>::add_back(void)
{
if (_size == _capacity)
reserve(_size + 1 + (_size >> 1));
return _data + _size++;
}
template <class T>
void vector<T>::push_back(const T & t)
{
new (add_back())T(t);
}
template <class T>
void vector<T>::push_back(T && t)
{
new (add_back())T(t);
}
template <class T>
template <typename ...P>
void vector<T>::emplace_back(const P&... p)
{
new (add_back())T(p...);
}
template <class T>
void vector<T>::assign(size_t count, const T & t)
{
for(size_t i=0; i<_size; i++)
_data[i].~T();
if (count > _capacity)
{
_size = 0;
reserve(count);
}
for(size_t i=0; i<count; i++)
new (_data + i)T(t);
_size = count;
}
template <class T>
void vector<T>::insert(size_t at, const T & t)
{
if (_size == _capacity)
reserve(_size + 1 + (_size >> 1));
new (_data + _size)T();
for(size_t i=_size; i>at; i--)
_data[i] = move(_data[i - 1]);
_data[at] = t;
_size++;
}
template <class T>
void vector<T>::erase(size_t at, size_t n)
{
_size -= n;
for(size_t i=at; i<_size; i++)
_data[i] = move(_data[i + n]);
for(size_t i=0; i<n; i++)
_data[_size + i].~T();
}
template <class T>
T * vector<T>::insert(T * at, const T & t)
{
if (_size == _capacity)
{
unsigned f = unsigned(at) - unsigned(_data);
reserve(_size + 1 + (_size >> 1));
at = (T *)(f + unsigned(_data));
}
T * dp = _data + _size;
new (dp)T();
while (dp != at)
{
dp--;
dp[1] = move(dp[0]);
}
dp[0] = t;
_size++;
return dp + 1;
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More