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