Prepare NES machine type
This commit is contained in:
parent
f34aa2dcbe
commit
6189e0cc49
|
@ -131,6 +131,9 @@ w0:
|
||||||
|
|
||||||
#elif defined(OSCAR_TARGET_BIN)
|
#elif defined(OSCAR_TARGET_BIN)
|
||||||
|
|
||||||
|
#elif defined(OSCAR_TARGET_NES)
|
||||||
|
sei
|
||||||
|
cld
|
||||||
#else
|
#else
|
||||||
byt 0x0b
|
byt 0x0b
|
||||||
byt 0x08
|
byt 0x08
|
||||||
|
@ -153,6 +156,7 @@ w0:
|
||||||
stx spentry
|
stx spentry
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Clear BSS Segment
|
// Clear BSS Segment
|
||||||
|
|
||||||
lda #<BSSStart
|
lda #<BSSStart
|
||||||
|
@ -239,6 +243,7 @@ bcode:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
spexit:
|
spexit:
|
||||||
|
#if !defined(OSCAR_TARGET_NES)
|
||||||
lda #$4c
|
lda #$4c
|
||||||
sta $54
|
sta $54
|
||||||
lda #0
|
lda #0
|
||||||
|
@ -248,6 +253,7 @@ spexit:
|
||||||
#if defined(__C128__)
|
#if defined(__C128__)
|
||||||
lda #0
|
lda #0
|
||||||
sta 0xff00
|
sta 0xff00
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
rts
|
rts
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,648 @@
|
||||||
|
#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
|
||||||
|
};
|
||||||
|
|
||||||
|
char OAM_BUF[256];
|
||||||
|
char PAL_BUF[32];
|
||||||
|
|
||||||
|
#pragma align(OAM_BUF, 256)
|
||||||
|
|
||||||
|
char NTSC_MODE;
|
||||||
|
volatile char FRAME_CNT1;
|
||||||
|
volatile char FRAME_CNT2;
|
||||||
|
char VRAM_UPDATE;
|
||||||
|
char * NAME_UPD_ADR;
|
||||||
|
char NAME_UPD_ENABLE;
|
||||||
|
char PAL_UPDATE;
|
||||||
|
const char * PAL_BG_PTR;
|
||||||
|
const char * PAL_SPR_PTR;
|
||||||
|
char SCROLL_X;
|
||||||
|
char SCROLL_Y;
|
||||||
|
char SCROLL_X1;
|
||||||
|
char SCROLL_Y1;
|
||||||
|
char PAD_STATE[2];
|
||||||
|
char PAD_STATEP[2];
|
||||||
|
char PAD_STATET[2];
|
||||||
|
char PPU_CTRL_VAR;
|
||||||
|
char PPU_CTRL_VAR1;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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] = 0;
|
||||||
|
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 attr + 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *)0x8000,
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
unsigned char get_ppu_ctrl_var(void);
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
void vram_adr(unsigned int adr);
|
||||||
|
|
||||||
|
// put a byte at current vram address, works only when rendering is turned off
|
||||||
|
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
|
||||||
|
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
|
|
@ -28,7 +28,7 @@ public:
|
||||||
|
|
||||||
DeclarationScope* mRuntimeScope;
|
DeclarationScope* mRuntimeScope;
|
||||||
|
|
||||||
LinkerSection* mSectionCode, * mSectionData, * mSectionBSS, * mSectionHeap, * mSectionStack, * mSectionZeroPage, * mSectionLowCode;
|
LinkerSection* mSectionCode, * mSectionData, * mSectionBSS, * mSectionHeap, * mSectionStack, * mSectionZeroPage, * mSectionLowCode, * mSectionBoot;
|
||||||
Linker* mLinker;
|
Linker* mLinker;
|
||||||
|
|
||||||
bool AddUnit(Location & location, const char* name, const char * from);
|
bool AddUnit(Location & location, const char* name, const char * from);
|
||||||
|
|
|
@ -23,6 +23,7 @@ Compiler::Compiler(void)
|
||||||
mCompilationUnits->mSectionStack = mLinker->AddSection(Ident::Unique("stack"), LST_STACK);
|
mCompilationUnits->mSectionStack = mLinker->AddSection(Ident::Unique("stack"), LST_STACK);
|
||||||
mCompilationUnits->mSectionZeroPage = mLinker->AddSection(Ident::Unique("zeropage"), LST_ZEROPAGE);
|
mCompilationUnits->mSectionZeroPage = mLinker->AddSection(Ident::Unique("zeropage"), LST_ZEROPAGE);
|
||||||
mCompilationUnits->mSectionLowCode = nullptr;
|
mCompilationUnits->mSectionLowCode = nullptr;
|
||||||
|
mCompilationUnits->mSectionBoot = nullptr;
|
||||||
mCompilationUnits->mSectionStack->mSize = 4096;
|
mCompilationUnits->mSectionStack->mSize = 4096;
|
||||||
mCompilationUnits->mSectionHeap->mSize = 1024;
|
mCompilationUnits->mSectionHeap->mSize = 1024;
|
||||||
|
|
||||||
|
@ -82,6 +83,11 @@ bool Compiler::ParseSource(void)
|
||||||
case TMACH_C128:
|
case TMACH_C128:
|
||||||
mCompilationUnits->mSectionLowCode = mLinker->AddSection(Ident::Unique("lowcode"), LST_DATA);
|
mCompilationUnits->mSectionLowCode = mLinker->AddSection(Ident::Unique("lowcode"), LST_DATA);
|
||||||
break;
|
break;
|
||||||
|
case TMACH_NES:
|
||||||
|
mCompilationUnits->mSectionStack->mSize = 256;
|
||||||
|
mCompilationUnits->mSectionHeap->mSize = 256;
|
||||||
|
mCompilationUnits->mSectionBoot = mLinker->AddSection(Ident::Unique("boot"), LST_DATA);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mPreprocessor->mCompilerOptions = mCompilerOptions;
|
mPreprocessor->mCompilerOptions = mCompilerOptions;
|
||||||
|
@ -194,6 +200,8 @@ bool Compiler::GenerateCode(void)
|
||||||
const Ident* identStartup = Ident::Unique("startup");
|
const Ident* identStartup = Ident::Unique("startup");
|
||||||
const Ident* identBytecode = Ident::Unique("bytecode");
|
const Ident* identBytecode = Ident::Unique("bytecode");
|
||||||
const Ident* identMain = Ident::Unique("main");
|
const Ident* identMain = Ident::Unique("main");
|
||||||
|
const Ident* identRom = Ident::Unique("rom");
|
||||||
|
const Ident* identBoot = Ident::Unique("boot");
|
||||||
const Ident* identCode = Ident::Unique("code");
|
const Ident* identCode = Ident::Unique("code");
|
||||||
const Ident* identZeroPage = Ident::Unique("zeropage");
|
const Ident* identZeroPage = Ident::Unique("zeropage");
|
||||||
const Ident* identLowcode = Ident::Unique("lowcode");
|
const Ident* identLowcode = Ident::Unique("lowcode");
|
||||||
|
@ -205,7 +213,7 @@ bool Compiler::GenerateCode(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkerRegion* regionStartup = mLinker->FindRegion(identStartup);
|
LinkerRegion* regionStartup = mLinker->FindRegion(identStartup);
|
||||||
LinkerRegion* regionLowcode = nullptr;
|
LinkerRegion* regionLowcode = nullptr, * regionBoot = nullptr;
|
||||||
|
|
||||||
if (!regionStartup)
|
if (!regionStartup)
|
||||||
{
|
{
|
||||||
|
@ -260,6 +268,8 @@ bool Compiler::GenerateCode(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (mTargetMachine == TMACH_NES)
|
||||||
|
regionStartup = mLinker->AddRegion(identStartup, 0x8000, 0x8080);
|
||||||
else
|
else
|
||||||
regionStartup = mLinker->AddRegion(identStartup, 0x0800, 0x0900);
|
regionStartup = mLinker->AddRegion(identStartup, 0x0800, 0x0900);
|
||||||
}
|
}
|
||||||
|
@ -296,6 +306,7 @@ bool Compiler::GenerateCode(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkerRegion* regionMain = mLinker->FindRegion(identMain);
|
LinkerRegion* regionMain = mLinker->FindRegion(identMain);
|
||||||
|
LinkerRegion* regionRom = mLinker->FindRegion(identRom);
|
||||||
|
|
||||||
LinkerSection * sectionStartup = mLinker->AddSection(identStartup, LST_DATA);
|
LinkerSection * sectionStartup = mLinker->AddSection(identStartup, LST_DATA);
|
||||||
LinkerSection* sectionBytecode = nullptr;
|
LinkerSection* sectionBytecode = nullptr;
|
||||||
|
@ -315,7 +326,14 @@ bool Compiler::GenerateCode(void)
|
||||||
{
|
{
|
||||||
if (!regionMain)
|
if (!regionMain)
|
||||||
{
|
{
|
||||||
if (!(mCompilerOptions & COPT_TARGET_PRG))
|
if (mTargetMachine == TMACH_NES)
|
||||||
|
{
|
||||||
|
regionBoot = mLinker->AddRegion(identBoot, 0xfffa, 0x10000);
|
||||||
|
regionBoot->mSections.Push(mCompilationUnits->mSectionBoot);
|
||||||
|
regionRom = mLinker->AddRegion(identRom, 0x8080, 0xfffa);
|
||||||
|
regionMain = mLinker->AddRegion(identMain, 0x0200, 0x0800);
|
||||||
|
}
|
||||||
|
else if (!(mCompilerOptions & COPT_TARGET_PRG))
|
||||||
regionMain = mLinker->AddRegion(identMain, 0x0900, 0x4700);
|
regionMain = mLinker->AddRegion(identMain, 0x0900, 0x4700);
|
||||||
else if (regionBytecode)
|
else if (regionBytecode)
|
||||||
{
|
{
|
||||||
|
@ -379,8 +397,17 @@ bool Compiler::GenerateCode(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (regionRom)
|
||||||
|
{
|
||||||
|
regionRom->mSections.Push(mCompilationUnits->mSectionCode);
|
||||||
|
regionRom->mSections.Push(mCompilationUnits->mSectionData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
regionMain->mSections.Push(mCompilationUnits->mSectionCode);
|
regionMain->mSections.Push(mCompilationUnits->mSectionCode);
|
||||||
regionMain->mSections.Push(mCompilationUnits->mSectionData);
|
regionMain->mSections.Push(mCompilationUnits->mSectionData);
|
||||||
|
}
|
||||||
|
|
||||||
regionMain->mSections.Push(mCompilationUnits->mSectionBSS);
|
regionMain->mSections.Push(mCompilationUnits->mSectionBSS);
|
||||||
regionMain->mSections.Push(mCompilationUnits->mSectionHeap);
|
regionMain->mSections.Push(mCompilationUnits->mSectionHeap);
|
||||||
regionMain->mSections.Push(mCompilationUnits->mSectionStack);
|
regionMain->mSections.Push(mCompilationUnits->mSectionStack);
|
||||||
|
@ -701,6 +728,13 @@ bool Compiler::WriteOutputFile(const char* targetPath, DiskImage * d64)
|
||||||
printf("Writing <%s>\n", prgPath);
|
printf("Writing <%s>\n", prgPath);
|
||||||
mLinker->WriteBinFile(prgPath);
|
mLinker->WriteBinFile(prgPath);
|
||||||
}
|
}
|
||||||
|
else if (mCompilerOptions & COPT_TARGET_NES)
|
||||||
|
{
|
||||||
|
strcat_s(prgPath, "nes");
|
||||||
|
if (mCompilerOptions & COPT_VERBOSE)
|
||||||
|
printf("Writing <%s>\n", prgPath);
|
||||||
|
mLinker->WriteNesFile(prgPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (d64)
|
if (d64)
|
||||||
|
|
|
@ -21,6 +21,7 @@ static const uint64 COPT_TARGET_CRT512 = 0x400000000ULL;
|
||||||
static const uint64 COPT_TARGET_COPY = 0x800000000ULL;
|
static const uint64 COPT_TARGET_COPY = 0x800000000ULL;
|
||||||
static const uint64 COPT_TARGET_BIN = 0x1000000000ULL;
|
static const uint64 COPT_TARGET_BIN = 0x1000000000ULL;
|
||||||
static const uint64 COPT_TARGET_LZO = 0x2000000000ULL;
|
static const uint64 COPT_TARGET_LZO = 0x2000000000ULL;
|
||||||
|
static const uint64 COPT_TARGET_NES = 0x4000000000ULL;
|
||||||
|
|
||||||
static const uint64 COPT_VERBOSE = 0x10000000000ULL;
|
static const uint64 COPT_VERBOSE = 0x10000000000ULL;
|
||||||
static const uint64 COPT_VERBOSE2 = 0x20000000000ULL;
|
static const uint64 COPT_VERBOSE2 = 0x20000000000ULL;
|
||||||
|
@ -46,7 +47,8 @@ enum TargetMachine
|
||||||
TMACH_VIC20_16K,
|
TMACH_VIC20_16K,
|
||||||
TMACH_VIC20_24K,
|
TMACH_VIC20_24K,
|
||||||
TMACH_C128,
|
TMACH_C128,
|
||||||
TMACH_C128B
|
TMACH_C128B,
|
||||||
|
TMACH_NES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -611,6 +611,25 @@ bool Linker::WriteBinFile(const char* filename)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Linker::WriteNesFile(const char* filename)
|
||||||
|
{
|
||||||
|
FILE* file;
|
||||||
|
fopen_s(&file, filename, "wb");
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
char header[16] = { 0x4e, 0x45, 0x53, 0x1a, 0x02, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00 };
|
||||||
|
|
||||||
|
fwrite(header, 1, 16, file);
|
||||||
|
int done = fwrite(mMemory + 0x8000, 1, 0x8000, file);
|
||||||
|
done += fwrite(mCartridge[0], 1, 0x2000, file);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return done == 0x8000 + 0x2000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Linker::WritePrgFile(DiskImage* image, const char* filename)
|
bool Linker::WritePrgFile(DiskImage* image, const char* filename)
|
||||||
{
|
{
|
||||||
if (image->OpenFile(filename))
|
if (image->OpenFile(filename))
|
||||||
|
|
|
@ -228,6 +228,7 @@ public:
|
||||||
bool WriteLblFile(const char* filename);
|
bool WriteLblFile(const char* filename);
|
||||||
bool WriteCrtFile(const char* filename);
|
bool WriteCrtFile(const char* filename);
|
||||||
bool WriteBinFile(const char* filename);
|
bool WriteBinFile(const char* filename);
|
||||||
|
bool WriteNesFile(const char* filename);
|
||||||
|
|
||||||
uint64 mCompilerOptions;
|
uint64 mCompilerOptions;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -186,6 +186,7 @@ public:
|
||||||
NativeCodeBasicBlock* mLoopHeadBlock, * mLoopTailBlock;
|
NativeCodeBasicBlock* mLoopHeadBlock, * mLoopTailBlock;
|
||||||
|
|
||||||
NativeRegisterDataSet mDataSet, mNDataSet, mFDataSet;
|
NativeRegisterDataSet mDataSet, mNDataSet, mFDataSet;
|
||||||
|
int mYAlias[256], mYOffset;
|
||||||
|
|
||||||
NativeCodeInstruction DecodeNative(LinkerObject * lobj, int& offset) const;
|
NativeCodeInstruction DecodeNative(LinkerObject * lobj, int& offset) const;
|
||||||
|
|
||||||
|
@ -428,6 +429,8 @@ public:
|
||||||
|
|
||||||
bool CrossBlockXYShortcut(void);
|
bool CrossBlockXYShortcut(void);
|
||||||
|
|
||||||
|
bool CrossBlockYAliasProgpagation(const int * yalias, int yoffset);
|
||||||
|
|
||||||
bool BypassRegisterConditionBlock(void);
|
bool BypassRegisterConditionBlock(void);
|
||||||
|
|
||||||
bool Check16BitSum(int at, NativeRegisterSum16Info& info);
|
bool Check16BitSum(int at, NativeRegisterSum16Info& info);
|
||||||
|
@ -515,6 +518,12 @@ public:
|
||||||
bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval);
|
bool CheckForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval);
|
||||||
bool PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval);
|
bool PatchForwardSumYPointer(const NativeCodeBasicBlock* block, int reg, int base, const NativeCodeInstruction & iins, int at, int yval);
|
||||||
|
|
||||||
|
bool CrossBlock16BitFlood(NativeCodeProcedure* proc);
|
||||||
|
bool CheckCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at, bool rvalid);
|
||||||
|
bool CheckCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg, bool rvalid);
|
||||||
|
bool PatchCrossBlock16BitFlood(const NativeCodeBasicBlock* block, int sreg, int dreg, int at);
|
||||||
|
bool PatchCrossBlock16BitFloodExit(const NativeCodeBasicBlock* block, int sreg, int dreg);
|
||||||
|
|
||||||
bool CrossBlockXYFlood(NativeCodeProcedure * proc);
|
bool CrossBlockXYFlood(NativeCodeProcedure * proc);
|
||||||
|
|
||||||
bool CheckCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at, bool rvalid);
|
bool CheckCrossBlockXFlood(const NativeCodeBasicBlock* block, int reg, int at, bool rvalid);
|
||||||
|
|
|
@ -282,11 +282,22 @@ int main2(int argc, const char** argv)
|
||||||
compiler->mTargetMachine = TMACH_VIC20_24K;
|
compiler->mTargetMachine = TMACH_VIC20_24K;
|
||||||
compiler->AddDefine(Ident::Unique("__VIC20__"), "1");
|
compiler->AddDefine(Ident::Unique("__VIC20__"), "1");
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(targetMachine, "nes"))
|
||||||
|
{
|
||||||
|
compiler->mTargetMachine = TMACH_NES;
|
||||||
|
compiler->mCompilerOptions |= COPT_EXTENDED_ZERO_PAGE;
|
||||||
|
compiler->AddDefine(Ident::Unique("__NES__"), "1");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid target machine option", targetMachine);
|
compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid target machine option", targetMachine);
|
||||||
|
|
||||||
|
|
||||||
if (!strcmp(targetFormat, "prg"))
|
if (compiler->mTargetMachine == TMACH_NES)
|
||||||
|
{
|
||||||
|
compiler->mCompilerOptions |= COPT_TARGET_NES;
|
||||||
|
compiler->AddDefine(Ident::Unique("OSCAR_TARGET_NES"), "1");
|
||||||
|
}
|
||||||
|
else if (!strcmp(targetFormat, "prg"))
|
||||||
{
|
{
|
||||||
compiler->mCompilerOptions |= COPT_TARGET_PRG;
|
compiler->mCompilerOptions |= COPT_TARGET_PRG;
|
||||||
compiler->AddDefine(Ident::Unique("OSCAR_TARGET_PRG"), "1");
|
compiler->AddDefine(Ident::Unique("OSCAR_TARGET_PRG"), "1");
|
||||||
|
|
Loading…
Reference in New Issue