add several incomplete experiments
- add code loading for m68k - incomplete scsp experiments - the register definitions should be fairly complete, though I did not produce actual sound yet - fix type.h definitions - incomplete cdblock register definitions
This commit is contained in:
parent
343f100a90
commit
6640c37a1d
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@
|
|||||||
*.elf
|
*.elf
|
||||||
*.bin
|
*.bin
|
||||||
*.gch
|
*.gch
|
||||||
|
*.out
|
||||||
|
5
Makefile
5
Makefile
@ -1,7 +1,7 @@
|
|||||||
AARCH = --isa=sh2 --big
|
AARCH = --isa=sh2 --big
|
||||||
AFLAGS = -g -gdwarf-4
|
AFLAGS = -g -gdwarf-4
|
||||||
CFLAGS += -ffunction-sections -fshort-enums -ffreestanding -nostdlib
|
CFLAGS += -ffunction-sections -fshort-enums -ffreestanding -nostdlib
|
||||||
CFLAGS += -Wall -Werror -Wfatal-errors -g -gdwarf-4 -Og
|
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -g -gdwarf-4 -Og
|
||||||
CARCH = -m2 -mb
|
CARCH = -m2 -mb
|
||||||
|
|
||||||
TARGET = sh2-none-elf-
|
TARGET = sh2-none-elf-
|
||||||
@ -48,8 +48,7 @@ SYS_IP_OBJ += smpsys.o
|
|||||||
|
|
||||||
sys_ip.elf: $(SYS_IP_OBJ)
|
sys_ip.elf: $(SYS_IP_OBJ)
|
||||||
|
|
||||||
MAIN_OBJ = main.o
|
MAIN_OBJ = main.o cd.o m68k/main.bin.o
|
||||||
#m68k/main.bin.o
|
|
||||||
|
|
||||||
main.elf: $(MAIN_OBJ)
|
main.elf: $(MAIN_OBJ)
|
||||||
$(LD) --print-memory-usage -T sh2.lds $^ -o $@
|
$(LD) --print-memory-usage -T sh2.lds $^ -o $@
|
||||||
|
111
cdblock.h
Normal file
111
cdblock.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include "type.h"
|
||||||
|
|
||||||
|
struct cr_rr {
|
||||||
|
reg16 val;
|
||||||
|
reg16 _res;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cdc_reg {
|
||||||
|
reg16 DTR;
|
||||||
|
reg8 _res0[6];
|
||||||
|
reg16 HIRQ;
|
||||||
|
reg16 _res1;
|
||||||
|
reg16 HMASK;
|
||||||
|
reg8 _res2[10];
|
||||||
|
union {
|
||||||
|
struct cr_rr CR[4];
|
||||||
|
struct cr_rr RR[4];
|
||||||
|
};
|
||||||
|
} cdc_reg;
|
||||||
|
|
||||||
|
static_assert((offsetof (struct cdc_reg, DTR)) == 0x00);
|
||||||
|
static_assert((offsetof (struct cdc_reg, HIRQ)) == 0x08);
|
||||||
|
static_assert((offsetof (struct cdc_reg, HMASK)) == 0x0c);
|
||||||
|
static_assert((offsetof (struct cdc_reg, RR)) == 0x18);
|
||||||
|
static_assert((offsetof (struct cdc_reg, RR[0].val)) == 0x18);
|
||||||
|
static_assert((offsetof (struct cdc_reg, RR[1].val)) == 0x1c);
|
||||||
|
static_assert((offsetof (struct cdc_reg, RR[2].val)) == 0x20);
|
||||||
|
static_assert((offsetof (struct cdc_reg, RR[3].val)) == 0x24);
|
||||||
|
static_assert((offsetof (struct cdc_reg, CR[0].val)) == 0x18);
|
||||||
|
static_assert((offsetof (struct cdc_reg, CR[1].val)) == 0x1c);
|
||||||
|
static_assert((offsetof (struct cdc_reg, CR[2].val)) == 0x20);
|
||||||
|
static_assert((offsetof (struct cdc_reg, CR[3].val)) == 0x24);
|
||||||
|
|
||||||
|
struct cdc {
|
||||||
|
cdc_reg reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct cdc cdc __asm("cdc");
|
||||||
|
|
||||||
|
#define CDC__HIRQ__MPST (1 << 13) // MPEG interrupt status
|
||||||
|
#define CDC__HIRQ__MPCM (1 << 12) // End of MPEG undefined operation section
|
||||||
|
#define CDC__HIRQ__MPED (1 << 11) // End of MPEG processing
|
||||||
|
#define CDC__HIRQ__SCDQ (1 << 10) // Subcode Q update complete
|
||||||
|
#define CDC__HIRQ__EFLS (1 << 9) // End of file system processing
|
||||||
|
#define CDC__HIRQ__ECPY (1 << 8) // End of copy/move process
|
||||||
|
#define CDC__HIRQ__EHST (1 << 7) // End of host I/O processing
|
||||||
|
#define CDC__HIRQ__ESEL (1 << 6) // End of selector setting process
|
||||||
|
#define CDC__HIRQ__DCHG (1 << 5) // Disk change occured
|
||||||
|
#define CDC__HIRQ__PEND (1 << 4) // End of CD playback
|
||||||
|
#define CDC__HIRQ__BFUL (1 << 3) // CD buffer full
|
||||||
|
#define CDC__HIRQ__CSCT (1 << 2) // 1 sector read complete
|
||||||
|
#define CDC__HIRQ__DRDY (1 << 1) // Ready for data transfer
|
||||||
|
#define CDC__HIRQ__CMOK (1 << 0) // Ready for command
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CMD__GET_CDSTATUS = 0x00,
|
||||||
|
CMD__GET_HWINFO = 0x01,
|
||||||
|
CMD__GET_TOC = 0x02,
|
||||||
|
CMD__GET_SESSINFO = 0x03,
|
||||||
|
CMD__INIT = 0x04,
|
||||||
|
CMD__OPEN = 0x05,
|
||||||
|
CMD__END_DATAXFER = 0x06,
|
||||||
|
|
||||||
|
CMD__PLAY = 0x10,
|
||||||
|
CMD__SEEK = 0x11,
|
||||||
|
CMD__SCAN = 0x12,
|
||||||
|
|
||||||
|
CMD__GET_SUBCODE = 0x20,
|
||||||
|
|
||||||
|
CMD__SET_CDDEVCONN = 0x30,
|
||||||
|
CMD__GET_CDDEVCONN = 0x31,
|
||||||
|
CMD__GET_LASTBUFDST = 0x32,
|
||||||
|
|
||||||
|
CMD__SET_FILTRANGE = 0x40,
|
||||||
|
CMD__GET_FILTRANGE = 0x41,
|
||||||
|
CMD__SET_FILTSUBHC = 0x42,
|
||||||
|
CMD__GET_FILTSUBHC = 0x43,
|
||||||
|
CMD__SET_FILTMODE = 0x44,
|
||||||
|
CMD__GET_FILTMODE = 0x45,
|
||||||
|
CMD__SET_FILTCONN = 0x46,
|
||||||
|
CMD__GET_FILTCONN = 0x47,
|
||||||
|
CMD__RESET_SEL = 0x48,
|
||||||
|
|
||||||
|
CMD__GET_BUFSIZE = 0x50,
|
||||||
|
CMD__GET_SECNUM = 0x51,
|
||||||
|
CMD__CALC_ACTSIZE = 0x52,
|
||||||
|
CMD__GET_ACTSIZE = 0x53,
|
||||||
|
CMD__GET_SECINFO = 0x54,
|
||||||
|
CMD__EXEC_FADSRCH = 0x55,
|
||||||
|
CMD__GET_FADSRCH = 0x56,
|
||||||
|
|
||||||
|
CMD__SET_SECLEN = 0x60,
|
||||||
|
CMD__GET_SECDATA = 0x61,
|
||||||
|
CMD__DEL_SECDATA = 0x62,
|
||||||
|
CMD__GETDEL_SECDATA = 0x63,
|
||||||
|
CMD__PUT_SECDATA = 0x64,
|
||||||
|
CMD__COPY_SECDATA = 0x65,
|
||||||
|
CMD__MOVE_SECDATA = 0x66,
|
||||||
|
CMD__GET_COPYERR = 0x67,
|
||||||
|
|
||||||
|
CMD__CHANGE_DIR = 0x70,
|
||||||
|
CMD__READ_DIR = 0x71,
|
||||||
|
CMD__GET_FSSCOPE = 0x72,
|
||||||
|
CMD__GET_FINFO = 0x73,
|
||||||
|
CMD__READ_FILE = 0x74,
|
||||||
|
CMD__ABORT_FILE = 0x75,
|
||||||
|
|
||||||
|
CMD__AUTH_DEVICE = 0xE0,
|
||||||
|
CMD__GET_AUTH = 0xE1
|
||||||
|
};
|
66
example/bitmap.c
Normal file
66
example/bitmap.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "vdp2.h"
|
||||||
|
#include "vdp1.h"
|
||||||
|
#include "scu.h"
|
||||||
|
#include "smpc.h"
|
||||||
|
#include "sh2.h"
|
||||||
|
#include "scsp.h"
|
||||||
|
#include "m68k.h"
|
||||||
|
|
||||||
|
void fill_32(u32 * buf, u32 v, s32 n)
|
||||||
|
{
|
||||||
|
while (n > 0) {
|
||||||
|
*buf++ = v;
|
||||||
|
n -= (sizeof (u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_16(u16 * src, u16 * dst, s32 n)
|
||||||
|
{
|
||||||
|
while (n > 0) {
|
||||||
|
*dst++ = *src++;
|
||||||
|
n -= (sizeof (u16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void put_pixel(int cx, int cy, u16 color)
|
||||||
|
{
|
||||||
|
#define CW 320
|
||||||
|
#define CH 240
|
||||||
|
int sx = (CW / 2) + cx;
|
||||||
|
int sy = (CH / 2) - cy;
|
||||||
|
vdp2.vram.u16[512 * sy + sx] = (1 << 15) | color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(void)
|
||||||
|
{
|
||||||
|
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
||||||
|
vdp2.reg.TVMD = ( TVMD__DISP | TVMD__LSMD__NON_INTERLACE
|
||||||
|
| TVMD__VRESO__240 | TVMD__HRESO__NORMAL_320);
|
||||||
|
|
||||||
|
//
|
||||||
|
// vdp2: bitmap mode
|
||||||
|
//
|
||||||
|
|
||||||
|
vdp2.reg.BGON = BGON__N0ON;
|
||||||
|
|
||||||
|
vdp2.reg.CHCTLA = ( CHCTLA__N0CHCN__32K_COLOR // 15 bits per pixel, RGB
|
||||||
|
| CHCTLA__N0BMSZ__512x256_DOT
|
||||||
|
| CHCTLA__N0BMEN__BITMAP_FORMAT
|
||||||
|
);
|
||||||
|
|
||||||
|
vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 2~0
|
||||||
|
// (boundary address value of the bit map pattern) =
|
||||||
|
// (map offset register value 3 bit) x 20000H
|
||||||
|
|
||||||
|
// zeroize NBG0 (black)
|
||||||
|
s32 plane_size = 512 * 256 * 2;
|
||||||
|
fill_32(&vdp2.vram.u32[0x0 / 4], (1 << 15) | (1 << 31), plane_size);
|
||||||
|
|
||||||
|
//vdp2.vram.u16[0x0 / 2] = (1 << 15) | 0x31;
|
||||||
|
//vdp2.vram.u16[((512 * 239 + 319) * 2) / 2] = (1 << 15) | 0x7fff;
|
||||||
|
|
||||||
|
put_pixel(0, 100, 0x3f);
|
||||||
|
put_pixel(0, 0, 0x7fff);
|
||||||
|
|
||||||
|
while (1) {}
|
||||||
|
}
|
37
example/cell.c
Normal file
37
example/cell.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// vdp2: define and place a single character on NBG0
|
||||||
|
//
|
||||||
|
|
||||||
|
vdp2.reg.BGON = BGON__N0ON;
|
||||||
|
|
||||||
|
vdp2.reg.CHCTLA = ( CHCTLA__N0CHCN__16_COLOR // 4 bits per pixel, palettized
|
||||||
|
| CHCTLA__N0BMEN__CELL_FORMAT
|
||||||
|
| CHCTLA__N0CHSZ__1x1_CELL
|
||||||
|
);
|
||||||
|
|
||||||
|
vdp2.reg.PNCN0 = PNCN0__N0PNB__2WORD;
|
||||||
|
|
||||||
|
vdp2.reg.PLSZ = PLSZ__N0PLSZ__1x1;
|
||||||
|
|
||||||
|
vdp2.vram.u16[16 + 0] = (1 << 12); // top left pixel of character # 1
|
||||||
|
vdp2.vram.u16[16 + 15] = (2 << 0 ); // bottom right pixel of character # 1
|
||||||
|
|
||||||
|
vdp2.cram.u16[1] = (0x31 << 5); // green
|
||||||
|
vdp2.cram.u16[2] = (0x31 << 10); // blue
|
||||||
|
|
||||||
|
// given:
|
||||||
|
// Plane Size: 1h X 1v
|
||||||
|
// Pattern Name Data Size: 2 Words
|
||||||
|
// only bits 5~0 are used for map address calculation
|
||||||
|
// so MPOFN is effectively ignored
|
||||||
|
vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 8~6
|
||||||
|
vdp2.reg.MPABN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(1); // bits 5~0
|
||||||
|
vdp2.reg.MPCDN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(1); // bits 5~0
|
||||||
|
|
||||||
|
// zeroize NBG0 plane; this should be less than 0x8000 above
|
||||||
|
s32 plane_size = 64 * 64 * 4; // is this correct ?
|
||||||
|
fill_32(&vdp2.vram.u32[(0x4000 / 4)], 0, plane_size);
|
||||||
|
|
||||||
|
// Table 4.8 Address value of map designated register by setting
|
||||||
|
// (bit 5~0) * 0x4000
|
||||||
|
vdp2.vram.u32[(0x4000 / 4)] = PATTERN_NAME_TABLE_2WORD__CHARACTER(1);
|
116
example/input.c
Normal file
116
example/input.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
void v_blank_in_int(void) __attribute__ ((interrupt_handler));
|
||||||
|
void v_blank_in_int(void)
|
||||||
|
{
|
||||||
|
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
||||||
|
|
||||||
|
// reset FRC to zero
|
||||||
|
sh2.reg.FRC.H = 0;
|
||||||
|
sh2.reg.FRC.L = 0;
|
||||||
|
|
||||||
|
// enable output compare interrupt
|
||||||
|
sh2.reg.TIER = TIER__OCIAE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oci_int(void) __attribute__ ((interrupt_handler));
|
||||||
|
void oci_int(void)
|
||||||
|
{
|
||||||
|
// clear OCFA
|
||||||
|
sh2.reg.FTCSR &= ~(FTCSR__OCFA);
|
||||||
|
|
||||||
|
while (smpc.reg.SF != 0) {}
|
||||||
|
|
||||||
|
smpc.reg.SF = 0;
|
||||||
|
|
||||||
|
smpc.reg.IREG0 = INTBACK__IREG0__STATUS_DISABLE;
|
||||||
|
smpc.reg.IREG1 = ( INTBACK__IREG1__PERIPHERAL_DATA_ENABLE
|
||||||
|
| INTBACK__IREG1__PORT2_0BYTE
|
||||||
|
| INTBACK__IREG1__PORT1_15BYTE
|
||||||
|
);
|
||||||
|
smpc.reg.IREG2 = INTBACK__IREG2__MAGIC;
|
||||||
|
|
||||||
|
smpc.reg.COMREG = COMREG__INTBACK;
|
||||||
|
|
||||||
|
// disable output compare interrupt (to be re-enabled on the next v_blank_in)
|
||||||
|
sh2.reg.TIER = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smpc_int(void) __attribute__ ((interrupt_handler));
|
||||||
|
void smpc_int(void)
|
||||||
|
{
|
||||||
|
scu.reg.IST &= ~(IST__SMPC);
|
||||||
|
|
||||||
|
if (smpc.reg.SR & SR__PDL) {
|
||||||
|
// to get all controller data, one should check SR__NPE and send CONTINUE
|
||||||
|
// requests as needed
|
||||||
|
|
||||||
|
// assuming SR__PDL is set and SR__P1MD is not 0-byte-mode:
|
||||||
|
// smpc.reg.OREG0 (port 1 status)
|
||||||
|
// smpc.reg.OREG1 (peripheral 1 data[0] {type,size})
|
||||||
|
// smpc.reg.OREG2 (peripheral 1 data[1])
|
||||||
|
|
||||||
|
if ((smpc.reg.OREG2 & DIGITAL__1__C) == 0) {
|
||||||
|
// if C is pressed, swap the color palette
|
||||||
|
vdp2.cram.u16[1] = (0x31 << 10); // blue
|
||||||
|
vdp2.cram.u16[2] = (0x31 << 5); // green
|
||||||
|
} else {
|
||||||
|
// if C is not pressed, restore the original palette
|
||||||
|
vdp2.cram.u16[1] = (0x31 << 5); // green
|
||||||
|
vdp2.cram.u16[2] = (0x31 << 10); // blue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
smpc.reg.IREG0 = INTBACK__IREG0__BREAK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// scu1:
|
||||||
|
//
|
||||||
|
|
||||||
|
// If timer0 is counting at roughly 15.73426 kHz (1/63.5556 µs), we can count
|
||||||
|
// to 300µs at roughly T0C = 5 (~317.778 µs). H-Blank-IN subtracts about
|
||||||
|
// 10.9µs which is still (~306 µs) more than 300µs.
|
||||||
|
|
||||||
|
vec[SCU_VEC__SMPC] = (u32)(&smpc_int);
|
||||||
|
vec[SCU_VEC__V_BLANK_IN] = (u32)(&v_blank_in_int);
|
||||||
|
//scu.reg.T0C = 5;
|
||||||
|
//scu.reg.T1MD = T1MD__TENB;
|
||||||
|
|
||||||
|
// From the SMPC manual:
|
||||||
|
// The SMPC uses the V-BLANK-IN interrupt to execute internal tasks. At this
|
||||||
|
// time, issuing commands for 300 µs from V-BLANK-IN is prohibited.
|
||||||
|
|
||||||
|
// CLKCHG320 (power-on default) NTSC, the FRC's internal clock is 26.8741 MHz.
|
||||||
|
// The possible periods are then:
|
||||||
|
//
|
||||||
|
// - 0.29768 µs (/8)
|
||||||
|
// - 1.19074 µs (/32)
|
||||||
|
// - 4.76295 µs (/128)
|
||||||
|
//
|
||||||
|
// (1/(26.8741 MHz)) * 128 * 63 = 300.066 µs
|
||||||
|
|
||||||
|
// FRC, OCRA, OCRB, and FCIR are 16-bit registers, but the FRT bus is an 8-bit
|
||||||
|
// bus.
|
||||||
|
|
||||||
|
// TCR set CKS to /128
|
||||||
|
// TOCR set OCRS to OCRA
|
||||||
|
// TIER set OCIAE
|
||||||
|
// FTCSR set CCLRA (clear FRC on compare match A)
|
||||||
|
// VCRC set FOCV
|
||||||
|
// OCRA set 63
|
||||||
|
// FRC set 0
|
||||||
|
|
||||||
|
vec[0x60] = (u32)&oci_int;
|
||||||
|
sh2.reg.VCRC = VCRC__FOCV(0x60);
|
||||||
|
|
||||||
|
sh2.reg.TCR = TCR__CKS__INTERNAL_DIV128;
|
||||||
|
sh2.reg.TOCR = TOCR__OCRS__OCRA;
|
||||||
|
sh2.reg.FTCSR = FTCSR__CCLRA;
|
||||||
|
sh2.reg.OCRAB.H = 0; // Even though Kronos doesn't emulate this, SH7095 says
|
||||||
|
// we are required to write the upper bit prior to
|
||||||
|
// writing the lower byte
|
||||||
|
sh2.reg.OCRAB.L = 63;
|
||||||
|
|
||||||
|
// reset/enable interrupts
|
||||||
|
scu.reg.IST = 0;
|
||||||
|
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
82
example/polygon.c
Normal file
82
example/polygon.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// vdp1:
|
||||||
|
//
|
||||||
|
|
||||||
|
// The VBE setting must be set immediately after the V-blank IN interrupt.
|
||||||
|
//
|
||||||
|
// TVM settings must be performed from the second H-blank IN interrupt after
|
||||||
|
// the V-blank IN interrupt to the H-blank IN interrupt immediately after the
|
||||||
|
// V-blank OUT interrupt.
|
||||||
|
vdp1.reg.TVMR = ( TVMR__TVM__NTSC_PAL
|
||||||
|
| TVMR__TVM__FRAMEBUFFER_NONROTATION
|
||||||
|
| TVMR__TVM__16BPP
|
||||||
|
);
|
||||||
|
|
||||||
|
// make FCM and FCT settings immediately after V-blank OUT
|
||||||
|
vdp1.reg.FBCR = 0;
|
||||||
|
|
||||||
|
// "A command table must always be stored at address 00000H to 0001EH."
|
||||||
|
// we can't trigger a plot yet because we have no (valid) table.
|
||||||
|
//vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
||||||
|
|
||||||
|
vdp1.reg.EWDR = 0; // black
|
||||||
|
|
||||||
|
// upper-left
|
||||||
|
vdp1.reg.EWLR = PTMR__EWLR__16BPP_X1(0) | PTMR__EWLR__Y1(0);
|
||||||
|
|
||||||
|
// lower-right
|
||||||
|
vdp1.reg.EWRR = PTMR__EWRR__16BPP_X3(319) | PTMR__EWRR__Y3(239);
|
||||||
|
|
||||||
|
vdp1.vram.cmd[0].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__USER_CLIP_COORDINATES;
|
||||||
|
vdp1.vram.cmd[0].LINK = 0;
|
||||||
|
vdp1.vram.cmd[0].XA = 0;
|
||||||
|
vdp1.vram.cmd[0].YA = 0;
|
||||||
|
vdp1.vram.cmd[0].XC = 319;
|
||||||
|
vdp1.vram.cmd[0].YC = 239;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[1].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__SYSTEM_CLIP_COORDINATES;
|
||||||
|
vdp1.vram.cmd[1].LINK = 0;
|
||||||
|
vdp1.vram.cmd[1].XC = 319;
|
||||||
|
vdp1.vram.cmd[1].YC = 239;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[2].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__LOCAL_COORDINATE;
|
||||||
|
vdp1.vram.cmd[2].LINK = 0;
|
||||||
|
vdp1.vram.cmd[2].XA = 0;
|
||||||
|
vdp1.vram.cmd[2].YA = 0;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[3].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
|
||||||
|
vdp1.vram.cmd[3].LINK = 0;
|
||||||
|
vdp1.vram.cmd[3].PMOD = CTRL__PMOD__ECD | CTRL__PMOD__SPD;
|
||||||
|
vdp1.vram.cmd[3].COLR = 0x2; // palette color #2
|
||||||
|
vdp1.vram.cmd[3].XA = 50;
|
||||||
|
vdp1.vram.cmd[3].YA = 50;
|
||||||
|
vdp1.vram.cmd[3].XB = 150;
|
||||||
|
vdp1.vram.cmd[3].YB = 50;
|
||||||
|
vdp1.vram.cmd[3].XC = 150;
|
||||||
|
vdp1.vram.cmd[3].YC = 150;
|
||||||
|
vdp1.vram.cmd[3].XD = 50;
|
||||||
|
vdp1.vram.cmd[3].YD = 150;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[4].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
|
||||||
|
vdp1.vram.cmd[4].LINK = 0;
|
||||||
|
vdp1.vram.cmd[4].PMOD = CTRL__PMOD__ECD | CTRL__PMOD__SPD;
|
||||||
|
vdp1.vram.cmd[4].COLR = (1 << 15) | (0x31 << 10) | (0x31 << 0); // RGB15 magenta
|
||||||
|
vdp1.vram.cmd[4].XA = 100;
|
||||||
|
vdp1.vram.cmd[4].YA = 50;
|
||||||
|
vdp1.vram.cmd[4].XB = 150;
|
||||||
|
vdp1.vram.cmd[4].YB = 100;
|
||||||
|
vdp1.vram.cmd[4].XC = 100;
|
||||||
|
vdp1.vram.cmd[4].YC = 150;
|
||||||
|
vdp1.vram.cmd[4].XD = 50;
|
||||||
|
vdp1.vram.cmd[4].YD = 100;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[5].CTRL = CTRL__END;
|
||||||
|
|
||||||
|
// priorities
|
||||||
|
vdp2.reg.PRISA = 0x0101;
|
||||||
|
vdp2.reg.PRISB = 0x0101;
|
||||||
|
vdp2.reg.PRISC = 0x0101;
|
||||||
|
vdp2.reg.PRISD = 0x0101;
|
||||||
|
|
||||||
|
// start drawing
|
||||||
|
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
30
example/sound.c
Normal file
30
example/sound.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// scsp
|
||||||
|
//
|
||||||
|
|
||||||
|
// The SCSP will initialize the internal registers, etc. for about 30µ sec
|
||||||
|
// after the reset has been released. For this reason, access is not allowed
|
||||||
|
// during the 30µ sec.
|
||||||
|
|
||||||
|
// Before downloading anything, make sure to set MEM4MB bit to 1 and DAC18B
|
||||||
|
// bit to 0 within the sound CPU (address) 10400H address.
|
||||||
|
|
||||||
|
smpc.reg.COMREG = COMREG__SNDON;
|
||||||
|
while (smpc.reg.OREG31 != 0b00000110) {}
|
||||||
|
for (long i = 0; i < 807; i++) { asm volatile ("nop"); } // wait for (way) more than 30µs
|
||||||
|
|
||||||
|
scsp.reg.common[0] = SCSP__0__MEM4MB | SCSP__0__DAC18B;
|
||||||
|
|
||||||
|
u16 * m68k_main_start = (u16 *)&_binary_m68k_main_bin_start;
|
||||||
|
u32 m68k_main_size = (u32)&_binary_m68k_main_bin_size;
|
||||||
|
copy_16(m68k_main_start, &scsp.ram.u16[0], m68k_main_size);
|
||||||
|
|
||||||
|
smpc.reg.COMREG = COMREG__SNDOFF;
|
||||||
|
while (smpc.reg.OREG31 != 0b00000111) {}
|
||||||
|
for (long i = 0; i < 807; i++) { asm volatile ("nop"); } // wait for (way) more than 30µs
|
||||||
|
|
||||||
|
smpc.reg.COMREG = COMREG__SNDON;
|
||||||
|
while (smpc.reg.OREG31 != 0b00000110) {}
|
||||||
|
for (long i = 0; i < 807; i++) { asm volatile ("nop"); } // wait for (way) more than 30µs
|
||||||
|
|
||||||
|
scsp.reg.common[0] = SCSP__0__MEM4MB | SCSP__0__DAC18B;
|
3
m68k.h
Normal file
3
m68k.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
extern unsigned long _binary_m68k_main_bin_end __asm("_binary_m68k_main_bin_end");
|
||||||
|
extern unsigned long _binary_m68k_main_bin_size __asm("_binary_m68k_main_bin_size");
|
||||||
|
extern unsigned long _binary_m68k_main_bin_start __asm("_binary_m68k_main_bin_start");
|
40
m68k/Makefile
Normal file
40
m68k/Makefile
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
ARCH = -march=68000 -mcpu=68ec000
|
||||||
|
AARCH = $(ARCH)
|
||||||
|
AFLAGS = -g -gdwarf-4
|
||||||
|
|
||||||
|
CFLAGS += -ffunction-sections -fshort-enums -ffreestanding -nostdlib
|
||||||
|
CFLAGS += -Wall -Werror -Wfatal-errors -g -gdwarf-4 -Og
|
||||||
|
CARCH = $(ARCH)
|
||||||
|
|
||||||
|
TARGET = m68k-none-elf-
|
||||||
|
CC = $(TARGET)gcc
|
||||||
|
AS = $(TARGET)as
|
||||||
|
LD = $(TARGET)ld
|
||||||
|
OBJCOPY = $(TARGET)objcopy
|
||||||
|
OBJDUMP = $(TARGET)objdump
|
||||||
|
|
||||||
|
all: main.bin
|
||||||
|
|
||||||
|
%.o: %.s
|
||||||
|
$(AS) $(AARCH) $(AFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
%.elf:
|
||||||
|
$(LD) --print-memory-usage -T m68k.lds $^ -o $@
|
||||||
|
|
||||||
|
%.bin: %.elf
|
||||||
|
$(OBJCOPY) -O binary $< $@
|
||||||
|
|
||||||
|
MAIN_OBJ = vectors.o main.o
|
||||||
|
|
||||||
|
main.elf: $(MAIN_OBJ)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.iso *.o *.bin *.elf
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.INTERMEDIATE:
|
||||||
|
.SECONDARY:
|
||||||
|
.PHONY: all clean
|
35
m68k/m68k.lds
Normal file
35
m68k/m68k.lds
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
|
||||||
|
OUTPUT_ARCH(m68k)
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
sound_ram : ORIGIN = 0x000000, LENGTH = 512K
|
||||||
|
}
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
. = 0x000000;
|
||||||
|
KEEP(*(.vectors))
|
||||||
|
*(.text)
|
||||||
|
} > sound_ram
|
||||||
|
|
||||||
|
.data ALIGN(4) : SUBALIGN(4)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
} > sound_ram
|
||||||
|
|
||||||
|
.rodata ALIGN(4) : SUBALIGN(4)
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
} > sound_ram
|
||||||
|
|
||||||
|
.bss ALIGN(4) (NOLOAD) : SUBALIGN(4)
|
||||||
|
{
|
||||||
|
*(.bss)
|
||||||
|
} > sound_ram
|
||||||
|
|
||||||
|
__bss_link_start = ADDR(.bss);
|
||||||
|
__bss_link_end = ADDR(.bss) + SIZEOF(.bss);
|
||||||
|
}
|
||||||
|
|
||||||
|
scsp = 0x000000;
|
12
m68k/main.c
Normal file
12
m68k/main.c
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "../scsp.h"
|
||||||
|
|
||||||
|
#define MVOL(n) (n << 0)
|
||||||
|
|
||||||
|
void start(void)
|
||||||
|
{
|
||||||
|
scsp.reg.common[0] = SCSP__0__MEM4MB | SCSP__0__DAC18B | MVOL(15);
|
||||||
|
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
67
m68k/vectors.s
Normal file
67
m68k/vectors.s
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
.section .vectors
|
||||||
|
|
||||||
|
.long 0x0 /* Reset - initial stack pointer */
|
||||||
|
.long start /* Reset - initial program counter */
|
||||||
|
.long start /* Bus error */
|
||||||
|
.long start /* Address error */
|
||||||
|
.long start /* Illegal command */
|
||||||
|
.long start /* Divide by zero */
|
||||||
|
.long start /* CHK exception */
|
||||||
|
.long start /* TRAPV exception */
|
||||||
|
.long start /* Privilege violation */
|
||||||
|
.long start /* Trace */
|
||||||
|
.long start /* Line 1010 emulator */
|
||||||
|
.long start /* Line 1111 emulator */
|
||||||
|
.long start /* reserved 12 */
|
||||||
|
.long start /* reserved 13 */
|
||||||
|
.long start /* reserved 14 */
|
||||||
|
.long start /* Uninitialized interrupt vector */
|
||||||
|
.long start /* reserved 16 */
|
||||||
|
.long start /* reserved 17 */
|
||||||
|
.long start /* reserved 18 */
|
||||||
|
.long start /* reserved 19 */
|
||||||
|
.long start /* reserved 20 */
|
||||||
|
.long start /* reserved 21 */
|
||||||
|
.long start /* reserved 22 */
|
||||||
|
.long start /* reserved 23 */
|
||||||
|
.long start /* Spurious interrupt */
|
||||||
|
.long start /* Auto vector level 1 interrupt */
|
||||||
|
.long start /* Auto vector level 2 interrupt */
|
||||||
|
.long start /* Auto vector level 3 interrupt */
|
||||||
|
.long start /* Auto vector level 4 interrupt */
|
||||||
|
.long start /* Auto vector level 5 interrupt */
|
||||||
|
.long start /* Auto vector level 6 interrupt */
|
||||||
|
.long start /* Auto vector level 7 interrupt */
|
||||||
|
.long start /* Trap #0 vector */
|
||||||
|
.long start /* Trap #1 vector */
|
||||||
|
.long start /* Trap #2 vector */
|
||||||
|
.long start /* Trap #3 vector */
|
||||||
|
.long start /* Trap #4 vector */
|
||||||
|
.long start /* Trap #5 vector */
|
||||||
|
.long start /* Trap #6 vector */
|
||||||
|
.long start /* Trap #7 vector */
|
||||||
|
.long start /* Trap #8 vector */
|
||||||
|
.long start /* Trap #9 vector */
|
||||||
|
.long start /* Trap #10 vector */
|
||||||
|
.long start /* Trap #11 vector */
|
||||||
|
.long start /* Trap #12 vector */
|
||||||
|
.long start /* Trap #13 vector */
|
||||||
|
.long start /* Trap #14 vector */
|
||||||
|
.long start /* Trap #15 vector */
|
||||||
|
.long start /* reserved 48 */
|
||||||
|
.long start /* reserved 49 */
|
||||||
|
.long start /* reserved 50 */
|
||||||
|
.long start /* reserved 51 */
|
||||||
|
.long start /* reserved 52 */
|
||||||
|
.long start /* reserved 53 */
|
||||||
|
.long start /* reserved 54 */
|
||||||
|
.long start /* reserved 55 */
|
||||||
|
.long start /* reserved 56 */
|
||||||
|
.long start /* reserved 57 */
|
||||||
|
.long start /* reserved 58 */
|
||||||
|
.long start /* reserved 59 */
|
||||||
|
.long start /* reserved 60 */
|
||||||
|
.long start /* reserved 61 */
|
||||||
|
.long start /* reserved 62 */
|
||||||
|
.long start /* reserved 63 */
|
||||||
|
.align 0x400, 0xee
|
281
main.c
281
main.c
@ -1,281 +0,0 @@
|
|||||||
#include "vdp2.h"
|
|
||||||
#include "vdp1.h"
|
|
||||||
#include "scu.h"
|
|
||||||
#include "smpc.h"
|
|
||||||
#include "sh2.h"
|
|
||||||
|
|
||||||
void fill_32(u32 * buf, u32 v, s32 n)
|
|
||||||
{
|
|
||||||
while (n > 0) {
|
|
||||||
*buf = v;
|
|
||||||
buf += 1;
|
|
||||||
n -= (sizeof (u32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer0_int(void) __attribute__ ((interrupt_handler));
|
|
||||||
void timer0_int(void)
|
|
||||||
{
|
|
||||||
scu.reg.IST &= ~(IST__TIMER0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void v_blank_in_int(void) __attribute__ ((interrupt_handler));
|
|
||||||
void v_blank_in_int(void)
|
|
||||||
{
|
|
||||||
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
|
||||||
|
|
||||||
// reset FRC to zero
|
|
||||||
sh2.reg.FRC.H = 0;
|
|
||||||
sh2.reg.FRC.L = 0;
|
|
||||||
|
|
||||||
// enable output compare interrupt
|
|
||||||
sh2.reg.TIER = TIER__OCIAE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void oci_int(void) __attribute__ ((interrupt_handler));
|
|
||||||
void oci_int(void)
|
|
||||||
{
|
|
||||||
// clear OCFA
|
|
||||||
sh2.reg.FTCSR &= ~(FTCSR__OCFA);
|
|
||||||
|
|
||||||
while (smpc.reg.SF != 0) {}
|
|
||||||
|
|
||||||
smpc.reg.SF = 0;
|
|
||||||
|
|
||||||
smpc.reg.IREG0 = INTBACK__IREG0__STATUS_DISABLE;
|
|
||||||
smpc.reg.IREG1 = ( INTBACK__IREG1__PERIPHERAL_DATA_ENABLE
|
|
||||||
| INTBACK__IREG1__PORT2_0BYTE
|
|
||||||
| INTBACK__IREG1__PORT1_15BYTE
|
|
||||||
);
|
|
||||||
smpc.reg.IREG2 = INTBACK__IREG2__MAGIC;
|
|
||||||
|
|
||||||
smpc.reg.COMREG = COMREG__INTBACK;
|
|
||||||
|
|
||||||
// disable output compare interrupt (to be re-enabled on the next v_blank_in)
|
|
||||||
sh2.reg.TIER = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void smpc_int(void) __attribute__ ((interrupt_handler));
|
|
||||||
void smpc_int(void)
|
|
||||||
{
|
|
||||||
scu.reg.IST &= ~(IST__SMPC);
|
|
||||||
|
|
||||||
if (smpc.reg.SR & SR__PDL) {
|
|
||||||
// to get all controller data, one should check SR__NPE and send CONTINUE
|
|
||||||
// requests as needed
|
|
||||||
|
|
||||||
// assuming SR__PDL is set and SR__P1MD is not 0-byte-mode:
|
|
||||||
// smpc.reg.OREG0 (port 1 status)
|
|
||||||
// smpc.reg.OREG1 (peripheral 1 data[0] {type,size})
|
|
||||||
// smpc.reg.OREG2 (peripheral 1 data[1])
|
|
||||||
|
|
||||||
if ((smpc.reg.OREG2 & DIGITAL__1__C) == 0) {
|
|
||||||
// if C is pressed, swap the color palette
|
|
||||||
vdp2.cram.u16[1] = (0x31 << 10); // blue
|
|
||||||
vdp2.cram.u16[2] = (0x31 << 5); // green
|
|
||||||
} else {
|
|
||||||
// if C is not pressed, restore the original palette
|
|
||||||
vdp2.cram.u16[1] = (0x31 << 5); // green
|
|
||||||
vdp2.cram.u16[2] = (0x31 << 10); // blue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
smpc.reg.IREG0 = INTBACK__IREG0__BREAK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start(void)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// vdp2: enable and set Back Screen color
|
|
||||||
//
|
|
||||||
|
|
||||||
vdp2.reg.TVMD = ( TVMD__DISP | TVMD__BDCLMD | TVMD__LSMD__NON_INTERLACE
|
|
||||||
| TVMD__VRESO__240 | TVMD__HRESO__NORMAL_320);
|
|
||||||
|
|
||||||
vdp2.reg.BGON = 0;
|
|
||||||
|
|
||||||
// BKTAU/BKTAL are shifted left 1: (0x4000 << 1 = 0x8000)
|
|
||||||
vdp2.reg.BKTA = REG_UL(BKTAU__BKCLMD_SINGLE_COLOR, 0x4000);
|
|
||||||
|
|
||||||
// background color, rgb15
|
|
||||||
vdp2.vram.u16[0x8000 / 2] = (0x05 << 0); // dark red
|
|
||||||
|
|
||||||
//
|
|
||||||
// vdp2: define and place a single character on NBG0
|
|
||||||
//
|
|
||||||
|
|
||||||
vdp2.reg.BGON = BGON__N0ON;
|
|
||||||
|
|
||||||
vdp2.reg.CHCTLA = ( CHCTLA__N0CHCN__16_COLOR // 4 bits per pixel, palettized
|
|
||||||
| CHCTLA__N0BMSZ__512x512_DOT
|
|
||||||
| CHCTLA__N0BMEN__CELL_FORMAT
|
|
||||||
| CHCTLA__N0CHSZ__1x1_CELL
|
|
||||||
);
|
|
||||||
|
|
||||||
vdp2.reg.PNCN0 = PNCN0__N0PNB__2WORD;
|
|
||||||
|
|
||||||
vdp2.reg.PLSZ = PLSZ__N0PLSZ__1x1;
|
|
||||||
|
|
||||||
vdp2.vram.u16[16 + 0] = (1 << 12); // top left pixel of character # 1
|
|
||||||
vdp2.vram.u16[16 + 15] = (2 << 0 ); // bottom right pixel of character # 1
|
|
||||||
|
|
||||||
vdp2.cram.u16[1] = (0x31 << 5); // green
|
|
||||||
vdp2.cram.u16[2] = (0x31 << 10); // blue
|
|
||||||
|
|
||||||
// given:
|
|
||||||
// Plane Size: 1h X 1v
|
|
||||||
// Pattern Name Data Size: 2 Words
|
|
||||||
// only bits 5~0 are used for map address calculation
|
|
||||||
// so MPOFN is effectively ignored
|
|
||||||
vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 8~6
|
|
||||||
vdp2.reg.MPABN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(1); // bits 5~0
|
|
||||||
vdp2.reg.MPCDN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(1); // bits 5~0
|
|
||||||
|
|
||||||
// zeroize NBG0 plane; this should be less than 0x8000 above
|
|
||||||
s32 plane_size = 64 * 64 * 4; // is this correct ?
|
|
||||||
fill_32(&vdp2.vram.u32[(0x4000 / 4)], 0, plane_size);
|
|
||||||
|
|
||||||
// Table 4.8 Address value of map designated register by setting
|
|
||||||
// (bit 5~0) * 0x4000
|
|
||||||
vdp2.vram.u32[(0x4000 / 4)] = PATTERN_NAME_TABLE_2WORD__CHARACTER(1);
|
|
||||||
|
|
||||||
//
|
|
||||||
// vdp1:
|
|
||||||
//
|
|
||||||
|
|
||||||
// The VBE setting must be set immediately after the V-blank IN interrupt.
|
|
||||||
//
|
|
||||||
// TVM settings must be performed from the second H-blank IN interrupt after
|
|
||||||
// the V-blank IN interrupt to the H-blank IN interrupt immediately after the
|
|
||||||
// V-blank OUT interrupt.
|
|
||||||
vdp1.reg.TVMR = ( TVMR__TVM__NTSC_PAL
|
|
||||||
| TVMR__TVM__FRAMEBUFFER_NONROTATION
|
|
||||||
| TVMR__TVM__16BPP
|
|
||||||
);
|
|
||||||
|
|
||||||
// make FCM and FCT settings immediately after V-blank OUT
|
|
||||||
vdp1.reg.FBCR = 0;
|
|
||||||
|
|
||||||
// "A command table must always be stored at address 00000H to 0001EH."
|
|
||||||
// we can't trigger a plot yet because we have no (valid) table.
|
|
||||||
//vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
|
||||||
|
|
||||||
vdp1.reg.EWDR = 0; // black
|
|
||||||
|
|
||||||
// upper-left
|
|
||||||
vdp1.reg.EWLR = PTMR__EWLR__16BPP_X1(0) | PTMR__EWLR__Y1(0);
|
|
||||||
|
|
||||||
// lower-right
|
|
||||||
vdp1.reg.EWRR = PTMR__EWRR__16BPP_X3(319) | PTMR__EWRR__Y3(239);
|
|
||||||
|
|
||||||
vdp1.vram.cmd[0].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__USER_CLIP_COORDINATES;
|
|
||||||
vdp1.vram.cmd[0].LINK = 0;
|
|
||||||
vdp1.vram.cmd[0].XA = 0;
|
|
||||||
vdp1.vram.cmd[0].YA = 0;
|
|
||||||
vdp1.vram.cmd[0].XC = 319;
|
|
||||||
vdp1.vram.cmd[0].YC = 239;
|
|
||||||
|
|
||||||
vdp1.vram.cmd[1].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__SYSTEM_CLIP_COORDINATES;
|
|
||||||
vdp1.vram.cmd[1].LINK = 0;
|
|
||||||
vdp1.vram.cmd[1].XC = 319;
|
|
||||||
vdp1.vram.cmd[1].YC = 239;
|
|
||||||
|
|
||||||
vdp1.vram.cmd[2].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__LOCAL_COORDINATE;
|
|
||||||
vdp1.vram.cmd[2].LINK = 0;
|
|
||||||
vdp1.vram.cmd[2].XA = 0;
|
|
||||||
vdp1.vram.cmd[2].YA = 0;
|
|
||||||
|
|
||||||
vdp1.vram.cmd[3].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
|
|
||||||
vdp1.vram.cmd[3].LINK = 0;
|
|
||||||
vdp1.vram.cmd[3].PMOD = CTRL__PMOD__ECD | CTRL__PMOD__SPD;
|
|
||||||
vdp1.vram.cmd[3].COLR = 0x2; // palette color #2
|
|
||||||
vdp1.vram.cmd[3].XA = 50;
|
|
||||||
vdp1.vram.cmd[3].YA = 50;
|
|
||||||
vdp1.vram.cmd[3].XB = 150;
|
|
||||||
vdp1.vram.cmd[3].YB = 50;
|
|
||||||
vdp1.vram.cmd[3].XC = 150;
|
|
||||||
vdp1.vram.cmd[3].YC = 150;
|
|
||||||
vdp1.vram.cmd[3].XD = 50;
|
|
||||||
vdp1.vram.cmd[3].YD = 150;
|
|
||||||
|
|
||||||
vdp1.vram.cmd[4].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
|
|
||||||
vdp1.vram.cmd[4].LINK = 0;
|
|
||||||
vdp1.vram.cmd[4].PMOD = CTRL__PMOD__ECD | CTRL__PMOD__SPD;
|
|
||||||
vdp1.vram.cmd[4].COLR = (1 << 15) | (0x31 << 10) | (0x31 << 0); // RGB15 magenta
|
|
||||||
vdp1.vram.cmd[4].XA = 100;
|
|
||||||
vdp1.vram.cmd[4].YA = 50;
|
|
||||||
vdp1.vram.cmd[4].XB = 150;
|
|
||||||
vdp1.vram.cmd[4].YB = 100;
|
|
||||||
vdp1.vram.cmd[4].XC = 100;
|
|
||||||
vdp1.vram.cmd[4].YC = 150;
|
|
||||||
vdp1.vram.cmd[4].XD = 50;
|
|
||||||
vdp1.vram.cmd[4].YD = 100;
|
|
||||||
|
|
||||||
vdp1.vram.cmd[5].CTRL = CTRL__END;
|
|
||||||
|
|
||||||
// priorities
|
|
||||||
vdp2.reg.PRISA = 0x0101;
|
|
||||||
vdp2.reg.PRISB = 0x0101;
|
|
||||||
vdp2.reg.PRISC = 0x0101;
|
|
||||||
vdp2.reg.PRISD = 0x0101;
|
|
||||||
|
|
||||||
// start drawing
|
|
||||||
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
|
||||||
|
|
||||||
//
|
|
||||||
// scu1:
|
|
||||||
//
|
|
||||||
|
|
||||||
// If timer0 is counting at roughly 15.73426 kHz (1/63.5556 µs), we can count
|
|
||||||
// to 300µs at roughly T0C = 5 (~317.778 µs). H-Blank-IN subtracts about
|
|
||||||
// 10.9µs which is still (~306 µs) more than 300µs.
|
|
||||||
|
|
||||||
vec[SCU_VEC__TIMER0] = (u32)(&timer0_int);
|
|
||||||
vec[SCU_VEC__SMPC] = (u32)(&smpc_int);
|
|
||||||
vec[SCU_VEC__V_BLANK_IN] = (u32)(&v_blank_in_int);
|
|
||||||
//scu.reg.T0C = 5;
|
|
||||||
//scu.reg.T1MD = T1MD__TENB;
|
|
||||||
|
|
||||||
// From the SMPC manual:
|
|
||||||
// The SMPC uses the V-BLANK-IN interrupt to execute internal tasks. At this
|
|
||||||
// time, issuing commands for 300 µs from V-BLANK-IN is prohibited.
|
|
||||||
|
|
||||||
// CLKCHG320 (power-on default) NTSC, the FRC's internal clock is 26.8741 MHz.
|
|
||||||
// The possible periods are then:
|
|
||||||
//
|
|
||||||
// - 0.29768 µs (/8)
|
|
||||||
// - 1.19074 µs (/32)
|
|
||||||
// - 4.76295 µs (/128)
|
|
||||||
//
|
|
||||||
// (1/(26.8741 MHz)) * 128 * 63 = 300.066 µs
|
|
||||||
|
|
||||||
// FRC, OCRA, OCRB, and FCIR are 16-bit registers, but the FRT bus is an 8-bit
|
|
||||||
// bus.
|
|
||||||
|
|
||||||
// TCR set CKS to /128
|
|
||||||
// TOCR set OCRS to OCRA
|
|
||||||
// TIER set OCIAE
|
|
||||||
// FTCSR set CCLRA (clear FRC on compare match A)
|
|
||||||
// VCRC set FOCV
|
|
||||||
// OCRA set 63
|
|
||||||
// FRC set 0
|
|
||||||
|
|
||||||
vec[0x60] = (u32)&oci_int;
|
|
||||||
sh2.reg.VCRC = VCRC__FOCV(0x60);
|
|
||||||
|
|
||||||
sh2.reg.TCR = TCR__CKS__INTERNAL_DIV128;
|
|
||||||
sh2.reg.TOCR = TOCR__OCRS__OCRA;
|
|
||||||
sh2.reg.FTCSR = FTCSR__CCLRA;
|
|
||||||
sh2.reg.OCRAB.H = 0; // Even though Kronos doesn't emulate this, SH7095 says
|
|
||||||
// we are required to write the upper bit prior to
|
|
||||||
// writing the lower byte
|
|
||||||
sh2.reg.OCRAB.L = 63;
|
|
||||||
|
|
||||||
// reset/enable interrupts
|
|
||||||
scu.reg.IST = 0;
|
|
||||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
vec[0] = scu.reg.IST;
|
|
||||||
}
|
|
||||||
}
|
|
68
scsp.h
Normal file
68
scsp.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "type.h"
|
||||||
|
|
||||||
|
// Because the main CPU cannot access in units of 8 bits, so read and write in
|
||||||
|
// 16 bit units.
|
||||||
|
//
|
||||||
|
// (presumably m68k can do 32-byte accesses)
|
||||||
|
|
||||||
|
typedef union scsp_ram {
|
||||||
|
unsigned short u16[0x080000 / 2];
|
||||||
|
unsigned long u32[0x080000 / 4];
|
||||||
|
} scsp_ram;
|
||||||
|
|
||||||
|
static_assert((sizeof (union scsp_ram)) == 0x080000);
|
||||||
|
|
||||||
|
typedef unsigned char scsp_res0[0x080000];
|
||||||
|
|
||||||
|
typedef struct scsp_slot {
|
||||||
|
reg16 field[0x18 / 2];
|
||||||
|
reg16 _res[0x8 / 2];
|
||||||
|
} scsp_slot;
|
||||||
|
|
||||||
|
static_assert((sizeof (struct scsp_slot)) == 0x20);
|
||||||
|
|
||||||
|
typedef struct scsp_dsp {
|
||||||
|
reg16 COEF[64];
|
||||||
|
reg16 MADRS[32];
|
||||||
|
reg16 _res[0x40 / 2];
|
||||||
|
reg16 micro[512];
|
||||||
|
reg16 internal[370];
|
||||||
|
} scsp_dsp;
|
||||||
|
|
||||||
|
static_assert((sizeof (struct scsp_dsp)) == 0x7e4);
|
||||||
|
|
||||||
|
typedef struct scsp_reg {
|
||||||
|
scsp_slot slot[32];
|
||||||
|
reg16 common[0x30 / 2];
|
||||||
|
reg16 _res0[0x1d0 / 2];
|
||||||
|
struct {
|
||||||
|
reg16 gen_a[32];
|
||||||
|
reg16 gen_b[32];
|
||||||
|
} direct;
|
||||||
|
reg16 _res1[0x80 / 2];
|
||||||
|
scsp_dsp dsp;
|
||||||
|
} scsp_reg;
|
||||||
|
|
||||||
|
static_assert((sizeof (struct scsp_reg)) == 0x000ee4);
|
||||||
|
static_assert((offsetof (struct scsp_reg, common)) == 0x000400);
|
||||||
|
static_assert((offsetof (struct scsp_reg, direct)) == 0x000600);
|
||||||
|
static_assert((offsetof (struct scsp_reg, dsp)) == 0x000700);
|
||||||
|
|
||||||
|
struct scsp {
|
||||||
|
scsp_ram ram;
|
||||||
|
scsp_res0 _res0;
|
||||||
|
scsp_reg reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct scsp scsp __asm("scsp");
|
||||||
|
|
||||||
|
static_assert((sizeof (struct scsp)) == 0x100ee4);
|
||||||
|
static_assert((offsetof (struct scsp, ram)) == 0x000000);
|
||||||
|
static_assert((offsetof (struct scsp, reg)) == 0x100000);
|
||||||
|
|
||||||
|
// bits
|
||||||
|
|
||||||
|
enum scsp_bits {
|
||||||
|
SCSP__0__MEM4MB = (1 << 9),
|
||||||
|
SCSP__0__DAC18B = (1 << 8),
|
||||||
|
};
|
1
sh2.lds
1
sh2.lds
@ -35,6 +35,7 @@ SECTIONS
|
|||||||
}
|
}
|
||||||
|
|
||||||
smpc = 0x00100000;
|
smpc = 0x00100000;
|
||||||
|
cdb = 0x05890000;
|
||||||
scsp = 0x05A00000;
|
scsp = 0x05A00000;
|
||||||
vdp1 = 0x05C00000;
|
vdp1 = 0x05C00000;
|
||||||
vdp2 = 0x05E00000;
|
vdp2 = 0x05E00000;
|
||||||
|
14
type.h
14
type.h
@ -9,13 +9,15 @@ static_assert((sizeof (reg8)) == 1);
|
|||||||
static_assert((sizeof (reg16)) == 2);
|
static_assert((sizeof (reg16)) == 2);
|
||||||
static_assert((sizeof (reg32)) == 4);
|
static_assert((sizeof (reg32)) == 4);
|
||||||
|
|
||||||
typedef volatile unsigned short u8;
|
typedef unsigned char u8;
|
||||||
typedef volatile short s8;
|
typedef char s8;
|
||||||
typedef volatile unsigned short u16;
|
typedef unsigned short u16;
|
||||||
typedef volatile short s16;
|
typedef short s16;
|
||||||
typedef volatile unsigned long u32;
|
typedef unsigned long u32;
|
||||||
typedef volatile long s32;
|
typedef long s32;
|
||||||
|
|
||||||
|
static_assert((sizeof (u8)) == 1);
|
||||||
|
static_assert((sizeof (s8)) == 1);
|
||||||
static_assert((sizeof (u16)) == 2);
|
static_assert((sizeof (u16)) == 2);
|
||||||
static_assert((sizeof (s16)) == 2);
|
static_assert((sizeof (s16)) == 2);
|
||||||
static_assert((sizeof (u32)) == 4);
|
static_assert((sizeof (u32)) == 4);
|
||||||
|
7
vdp2.h
7
vdp2.h
@ -219,8 +219,9 @@ enum tvmd_bit {
|
|||||||
enum tvstat_bit {
|
enum tvstat_bit {
|
||||||
TVSTAT__VBLANK = (1 << 3),
|
TVSTAT__VBLANK = (1 << 3),
|
||||||
};
|
};
|
||||||
// enum vrsize_bit {
|
enum vrsize_bit {
|
||||||
// };
|
VRSIZE__VRAMSZ = (1 << 15),
|
||||||
|
};
|
||||||
// enum hcnt_bit {
|
// enum hcnt_bit {
|
||||||
// };
|
// };
|
||||||
// enum vcnt_bit {
|
// enum vcnt_bit {
|
||||||
@ -292,7 +293,7 @@ enum chctla_bit {
|
|||||||
CHCTLA__N0BMSZ__1024x512_DOT = (0b11 << 2),
|
CHCTLA__N0BMSZ__1024x512_DOT = (0b11 << 2),
|
||||||
|
|
||||||
CHCTLA__N0BMEN__CELL_FORMAT = (0 << 1),
|
CHCTLA__N0BMEN__CELL_FORMAT = (0 << 1),
|
||||||
CHCTLA__N0BMEN__BITMAP_FORMAT = (0 << 1),
|
CHCTLA__N0BMEN__BITMAP_FORMAT = (1 << 1),
|
||||||
|
|
||||||
CHCTLA__N0CHSZ__1x1_CELL = (0 << 0),
|
CHCTLA__N0CHSZ__1x1_CELL = (0 << 0),
|
||||||
CHCTLA__N0CHSZ__2x2_CELL = (1 << 0),
|
CHCTLA__N0CHSZ__2x2_CELL = (1 << 0),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user