sound_cpu__interrupt: add slot visuals
This shows the value of some of the most relevant SCSP slot fields.
This commit is contained in:
parent
3358d95704
commit
3b82199d08
10
Makefile
10
Makefile
@ -3,7 +3,7 @@ OPT = -Og
|
|||||||
LIBGCC = $(shell $(CC) -print-file-name=libgcc.a)
|
LIBGCC = $(shell $(CC) -print-file-name=libgcc.a)
|
||||||
LIB = ./saturn
|
LIB = ./saturn
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
||||||
include $(LIB)/common.mk
|
include $(LIB)/common.mk
|
||||||
|
|
||||||
@ -51,6 +51,9 @@ res/dejavusansmono.font.bin: tools/ttf-convert
|
|||||||
res/ipapgothic.font.bin: tools/ttf-convert
|
res/ipapgothic.font.bin: tools/ttf-convert
|
||||||
./tools/ttf-convert 3000 30ff 28 $(shell fc-match -f '%{file}' 'IPAPGothic') $@
|
./tools/ttf-convert 3000 30ff 28 $(shell fc-match -f '%{file}' 'IPAPGothic') $@
|
||||||
|
|
||||||
|
res/sperrypc.font.bin: tools/ttf-convert
|
||||||
|
./tools/ttf-convert 20 7f 8 res/Bm437_SperryPC_CGA.otb $@
|
||||||
|
|
||||||
common/keyboard.hpp: common/keyboard.py
|
common/keyboard.hpp: common/keyboard.py
|
||||||
python common/keyboard.py header > $@
|
python common/keyboard.py header > $@
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ m68k/%.bin: m68k
|
|||||||
|
|
||||||
scsp/sound_cpu__slot.elf: scsp/sound_cpu__slot.o m68k/slot.bin.o
|
scsp/sound_cpu__slot.elf: scsp/sound_cpu__slot.o m68k/slot.bin.o
|
||||||
|
|
||||||
scsp/sound_cpu__interrupt.elf: scsp/sound_cpu__interrupt.o m68k/interrupt.bin.o
|
scsp/sound_cpu__interrupt.elf: scsp/sound_cpu__interrupt.o m68k/interrupt.bin.o sh/lib1funcs.o res/sperrypc.font.bin.o common/draw_font.o common/palette.o
|
||||||
|
|
||||||
# clean
|
# clean
|
||||||
clean: clean-sh
|
clean: clean-sh
|
||||||
@ -101,6 +104,7 @@ clean-sh:
|
|||||||
common/keyboard.cpp \
|
common/keyboard.cpp \
|
||||||
common/keyboard.hpp \
|
common/keyboard.hpp \
|
||||||
wordle/word_list.hpp
|
wordle/word_list.hpp
|
||||||
|
make -C tools clean
|
||||||
|
make -C m68k clean
|
||||||
|
|
||||||
PHONY: m68k tools
|
PHONY: m68k tools
|
||||||
|
@ -14,12 +14,13 @@ struct state {
|
|||||||
uint32_t font_data(void * buf, uint32_t top, state& state);
|
uint32_t font_data(void * buf, uint32_t top, state& state);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
uint32_t horizontal_string(state const& s,
|
inline
|
||||||
uint32_t& cmd_ix,
|
int32_t horizontal_string(state const& s,
|
||||||
const T * string,
|
uint32_t& cmd_ix,
|
||||||
const uint32_t length,
|
const T * string,
|
||||||
const int32_t x,
|
const uint32_t length,
|
||||||
const int32_t y)
|
const int32_t x,
|
||||||
|
const int32_t y)
|
||||||
{
|
{
|
||||||
int32_t total_advance = 0;
|
int32_t total_advance = 0;
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ uint32_t horizontal_string(state const& s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
inline
|
||||||
uint32_t single_character_centered(state const& s,
|
uint32_t single_character_centered(state const& s,
|
||||||
uint32_t cmd_ix,
|
uint32_t cmd_ix,
|
||||||
const T c,
|
const T c,
|
||||||
|
@ -2,7 +2,7 @@ CFLAGS = -I../saturn
|
|||||||
OPT = -Og
|
OPT = -Og
|
||||||
LIB = ../saturn
|
LIB = ../saturn
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
||||||
include $(LIB)/m68k/common.mk
|
include $(LIB)/m68k/common.mk
|
||||||
|
|
||||||
|
@ -4,13 +4,15 @@
|
|||||||
|
|
||||||
extern void * _jojo_start __asm("_binary_jojo_11025_s16be_1ch_pcm_start");
|
extern void * _jojo_start __asm("_binary_jojo_11025_s16be_1ch_pcm_start");
|
||||||
|
|
||||||
static volatile int32_t frame = 0;
|
static volatile int32_t frame = 0x0;
|
||||||
|
|
||||||
constexpr int32_t tactl = 7;
|
constexpr int32_t tactl = 7;
|
||||||
constexpr int32_t frame_size = ((1 << tactl) * 256) / (44100 / 11025);
|
constexpr int32_t frame_size = ((1 << tactl) * 256) / (44100 / 11025);
|
||||||
constexpr int32_t frame_count = 507150 / (frame_size * 2);
|
constexpr int32_t frame_count = 507150 / (frame_size * 2);
|
||||||
constexpr int32_t tima = 0;
|
constexpr int32_t tima = 0;
|
||||||
|
|
||||||
|
static uint16_t slot_ix = 0;
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
void auto_vector_1(void) __attribute__ ((interrupt_handler));
|
void auto_vector_1(void) __attribute__ ((interrupt_handler));
|
||||||
void auto_vector_1(void)
|
void auto_vector_1(void)
|
||||||
@ -20,15 +22,16 @@ void auto_vector_1(void)
|
|||||||
scsp.reg.ctrl.TIMA = TIMA__TACTL(tactl) | TIMA__TIMA(tima);
|
scsp.reg.ctrl.TIMA = TIMA__TACTL(tactl) | TIMA__TIMA(tima);
|
||||||
|
|
||||||
if (frame > frame_count) frame = 0;
|
if (frame > frame_count) frame = 0;
|
||||||
|
|
||||||
const uint16_t * jojo_start = reinterpret_cast<uint16_t *>(&_jojo_start);
|
const uint16_t * jojo_start = reinterpret_cast<uint16_t *>(&_jojo_start);
|
||||||
const uint32_t frame_addr = reinterpret_cast<uint32_t>(&jojo_start[frame * frame_size]);
|
const uint32_t frame_addr = reinterpret_cast<uint32_t>(&jojo_start[frame * frame_size]);
|
||||||
|
|
||||||
scsp_slot& slotp = scsp.reg.slot[(frame - 1) % 32];
|
scsp_slot& slotp = scsp.reg.slot[(slot_ix - 1) & 31];
|
||||||
slotp.LOOP = 0;
|
slotp.LOOP = 0;
|
||||||
slotp.LOOP |= LOOP__KYONEX;
|
slotp.LOOP |= LOOP__KYONEX;
|
||||||
|
|
||||||
scsp_slot& slot = scsp.reg.slot[(frame) % 32];
|
scsp.reg.ctrl.STATUS = STATUS__MSLC(slot_ix & 31);
|
||||||
|
scsp_slot& slot = scsp.reg.slot[slot_ix & 31];
|
||||||
slot.LOOP = LOOP__KYONB | LOOP__SA(frame_addr); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:16]
|
slot.LOOP = LOOP__KYONB | LOOP__SA(frame_addr); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:16]
|
||||||
slot.SA = SA__SA(frame_addr); // start address (bytes)
|
slot.SA = SA__SA(frame_addr); // start address (bytes)
|
||||||
slot.LSA = 0; // loop start address (samples)
|
slot.LSA = 0; // loop start address (samples)
|
||||||
@ -42,54 +45,45 @@ void auto_vector_1(void)
|
|||||||
|
|
||||||
slot.LOOP |= LOOP__KYONEX;
|
slot.LOOP |= LOOP__KYONEX;
|
||||||
|
|
||||||
|
scsp.ram.u32[0] = (0xdead << 16) | (slot_ix);
|
||||||
|
scsp.ram.u32[1] = frame;
|
||||||
frame++;
|
frame++;
|
||||||
|
slot_ix++;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
for (long i = 0; i < 807; i++) { asm volatile ("nop"); } // wait for (way) more than 30µs
|
for (long i = 0; i < 807; i++) { asm volatile ("nop"); } // wait for (way) more than 30µs
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
scsp_slot& slot = scsp.reg.slot[i];
|
scsp_slot& slot = scsp.reg.slot[i];
|
||||||
slot.LOOP = 0;
|
slot.LOOP = 0;
|
||||||
|
slot.SA = 0;
|
||||||
|
slot.LSA = 0;
|
||||||
|
slot.LEA = 0;
|
||||||
|
slot.EG = 0;
|
||||||
|
slot.VOLUME = 0;
|
||||||
|
slot.FM = 0;
|
||||||
|
slot.PITCH = 0;
|
||||||
|
slot.LFO = 0;
|
||||||
|
slot.MIXER = 0;
|
||||||
slot.LOOP |= LOOP__KYONEX;
|
slot.LOOP |= LOOP__KYONEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB | MIXER__MVOL(0xf);
|
scsp.reg.ctrl.MIXER = MIXER__MEM4MB | MIXER__MVOL(0xf);
|
||||||
|
|
||||||
// timer A is vector 1 (0b001)
|
// timer A is vector 1 (0b001)
|
||||||
scsp.reg.ctrl.SCILV2 = 0;
|
scsp.reg.ctrl.SCILV2 = 0;
|
||||||
scsp.reg.ctrl.SCILV1 = 0;
|
scsp.reg.ctrl.SCILV1 = 0;
|
||||||
scsp.reg.ctrl.SCILV0 = SCILV__TIMER_A;
|
scsp.reg.ctrl.SCILV0 = SCILV__TIMER_A;
|
||||||
|
|
||||||
// enable TIMER_A
|
// enable TIMER_A
|
||||||
scsp.reg.ctrl.SCIRE = INT__TIMER_A;
|
scsp.reg.ctrl.SCIRE = INT__TIMER_A;
|
||||||
scsp.reg.ctrl.SCIEB = INT__TIMER_A;
|
scsp.reg.ctrl.SCIEB = INT__TIMER_A;
|
||||||
|
|
||||||
scsp.reg.ctrl.TIMA = TIMA__TACTL(tactl) | TIMA__TIMA(tima);
|
scsp.reg.ctrl.TIMA = TIMA__TACTL(tactl) | TIMA__TIMA(tima);
|
||||||
|
|
||||||
asm volatile ("move.w #8192,%sr");
|
asm volatile ("move.w #8192,%sr");
|
||||||
|
|
||||||
/*
|
|
||||||
const uint16_t * jojo_start = reinterpret_cast<uint16_t *>(&_jojo_start);
|
|
||||||
const uint32_t frame_addr = reinterpret_cast<uint32_t>(&jojo_start[frame * 128]);
|
|
||||||
scsp_slot& slot = scsp.reg.slot[0];
|
|
||||||
slot.LOOP = 0;
|
|
||||||
slot.LOOP |= LOOP__KYONEX;
|
|
||||||
|
|
||||||
slot.LOOP = LOOP__KYONB | LOOP__SA(frame_addr); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:16]
|
|
||||||
slot.SA = SA__SA(frame_addr); // start address (bytes)
|
|
||||||
slot.LSA = 0; // loop start address (samples)
|
|
||||||
slot.LEA = 128; // loop end address (samples)
|
|
||||||
slot.EG = EG__AR(0x1f) | EG__EGHOLD; // d2r d1r ho ar krs dl rr
|
|
||||||
slot.VOLUME = 0; // stwinh sdir tl
|
|
||||||
slot.FM = 0; // mdl mdxsl mdysl
|
|
||||||
slot.PITCH = PITCH__OCT(-2) | PITCH__FNS(0); // oct fns
|
|
||||||
slot.LFO = 0; // lfof plfows
|
|
||||||
slot.MIXER = MIXER__DISDL(0b101); // disdl dipan efsdl efpan
|
|
||||||
|
|
||||||
slot.LOOP |= LOOP__KYONEX;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ void main()
|
|||||||
scsp_slot& slot = scsp.reg.slot[0];
|
scsp_slot& slot = scsp.reg.slot[0];
|
||||||
slot.LOOP = 0;
|
slot.LOOP = 0;
|
||||||
slot.LOOP |= LOOP__KYONEX;
|
slot.LOOP |= LOOP__KYONEX;
|
||||||
|
|
||||||
slot.LOOP = LOOP__KYONB | LOOP__LPCTL__NORMAL | LOOP__SA(sine_start); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:16]
|
slot.LOOP = LOOP__KYONB | LOOP__LPCTL__NORMAL | LOOP__SA(sine_start); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:16]
|
||||||
slot.SA = SA__SA(sine_start); // start address (bytes)
|
slot.SA = SA__SA(sine_start); // start address (bytes)
|
||||||
slot.LSA = 0; // loop start address (samples)
|
slot.LSA = 0; // loop start address (samples)
|
||||||
|
BIN
res/Bm437_SperryPC_CGA.otb
Normal file
BIN
res/Bm437_SperryPC_CGA.otb
Normal file
Binary file not shown.
@ -2,13 +2,80 @@
|
|||||||
|
|
||||||
#include "smpc.h"
|
#include "smpc.h"
|
||||||
#include "scsp.h"
|
#include "scsp.h"
|
||||||
|
#include "vdp1.h"
|
||||||
|
#include "vdp2.h"
|
||||||
|
#include "scu.h"
|
||||||
|
#include "sh2.h"
|
||||||
|
|
||||||
#include "../common/copy.hpp"
|
#include "../common/copy.hpp"
|
||||||
|
#include "../common/font.hpp"
|
||||||
|
#include "../common/draw_font.hpp"
|
||||||
|
#include "../common/palette.hpp"
|
||||||
|
#include "../common/vdp2_func.hpp"
|
||||||
|
|
||||||
extern void * _m68k_start __asm("_binary_m68k_interrupt_bin_start");
|
extern void * _m68k_start __asm("_binary_m68k_interrupt_bin_start");
|
||||||
extern void * _m68k_size __asm("_binary_m68k_interrupt_bin_size");
|
extern void * _m68k_size __asm("_binary_m68k_interrupt_bin_size");
|
||||||
|
extern void * _sperrypc_start __asm("_binary_res_sperrypc_font_bin_start");
|
||||||
|
|
||||||
void main()
|
struct draw_state {
|
||||||
|
uint32_t cmd_ix;
|
||||||
|
struct draw_font::state font;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct draw_state draw_state;
|
||||||
|
|
||||||
|
uint32_t print_hex(uint8_t * c, uint32_t len, uint32_t n)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
uint32_t nib = n & 0xf;
|
||||||
|
n = n >> 4;
|
||||||
|
|
||||||
|
if (nib > 9) {
|
||||||
|
nib += (97 - 10);
|
||||||
|
} else {
|
||||||
|
nib += (48 - 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
c[--len] = nib;
|
||||||
|
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t draw_string(const uint8_t * string,
|
||||||
|
const uint32_t length,
|
||||||
|
const int32_t x,
|
||||||
|
const int32_t y)
|
||||||
|
{
|
||||||
|
return draw_font::horizontal_string(draw_state.font,
|
||||||
|
draw_state.cmd_ix,
|
||||||
|
string,
|
||||||
|
length,
|
||||||
|
(x ),
|
||||||
|
((y + 1) * 8) << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t init_font(uint32_t top)
|
||||||
|
{
|
||||||
|
// 256 is the number of colors in the color palette, not the number of grays
|
||||||
|
// that are used by the font.
|
||||||
|
constexpr uint32_t colors_per_palette = 256;
|
||||||
|
constexpr uint32_t color_bank_index = 0; // completely random and arbitrary value
|
||||||
|
|
||||||
|
palette::vdp2_cram_32grays(colors_per_palette, color_bank_index);
|
||||||
|
// For color bank color, COLR is concatenated bitwise with pixel data. See
|
||||||
|
// Figure 6.17 in the VDP1 manual.
|
||||||
|
draw_state.font.color_address = color_bank_index << 8;
|
||||||
|
|
||||||
|
top = font_data(&_sperrypc_start, top, draw_state.font);
|
||||||
|
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_sound()
|
||||||
{
|
{
|
||||||
/* SEGA SATURN TECHNICAL BULLETIN # 51
|
/* SEGA SATURN TECHNICAL BULLETIN # 51
|
||||||
|
|
||||||
@ -23,6 +90,12 @@ void main()
|
|||||||
|
|
||||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB;
|
scsp.reg.ctrl.MIXER = MIXER__MEM4MB;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The Saturn BIOS does not (un)initialize the DSP. Without zeroizing the DSP
|
||||||
|
program, the SCSP DSP appears to have a program that continuously writes to
|
||||||
|
0x30000 through 0x3ffff in sound RAM, which has the effect of destroying any
|
||||||
|
samples stored there.
|
||||||
|
*/
|
||||||
reg32 * dsp_steps = reinterpret_cast<reg32*>(&(scsp.reg.dsp.STEP[0].MPRO[0]));
|
reg32 * dsp_steps = reinterpret_cast<reg32*>(&(scsp.reg.dsp.STEP[0].MPRO[0]));
|
||||||
fill<reg32>(dsp_steps, 0, (sizeof (scsp.reg.dsp.STEP)));
|
fill<reg32>(dsp_steps, 0, (sizeof (scsp.reg.dsp.STEP)));
|
||||||
|
|
||||||
@ -34,8 +107,157 @@ void main()
|
|||||||
smpc.reg.SF = 1;
|
smpc.reg.SF = 1;
|
||||||
smpc.reg.COMREG = COMREG__SNDON;
|
smpc.reg.COMREG = COMREG__SNDON;
|
||||||
while (smpc.reg.oreg[31] != OREG31__SNDON);
|
while (smpc.reg.oreg[31] != OREG31__SNDON);
|
||||||
|
}
|
||||||
|
|
||||||
// do nothing while the sound CPU manipulates the SCSP
|
static inline void init_vdp()
|
||||||
|
{
|
||||||
|
// wait for the beginning of a V blank
|
||||||
|
v_blank_in();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// disable all VDP2 backgrounds (e.g: the Sega bios logo)
|
||||||
|
vdp2.reg.BGON = 0;
|
||||||
|
|
||||||
|
// zeroize BACK color
|
||||||
|
vdp2.reg.BKTAU = 0;
|
||||||
|
vdp2.reg.BKTAL = 0;
|
||||||
|
vdp2.vram.u16[0] = 0;
|
||||||
|
|
||||||
|
vdp2.reg.PRISA = PRISA__S0PRIN(1); // Sprite register 0 PRIority Number
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
// "normal" display resolution, 16 bits per pixel, 512x256 framebuffer
|
||||||
|
vdp1.reg.TVMR = TVMR__TVM__NORMAL;
|
||||||
|
|
||||||
|
// swap framebuffers every 1 cycle; non-interlace
|
||||||
|
vdp1.reg.FBCR = 0;
|
||||||
|
|
||||||
|
// during a framebuffer erase cycle, write the color "black" to each pixel
|
||||||
|
constexpr uint16_t black = 0x0000;
|
||||||
|
vdp1.reg.EWDR = black;
|
||||||
|
|
||||||
|
// erase upper-left coordinate
|
||||||
|
vdp1.reg.EWLR = EWLR__16BPP_X1(0) | EWLR__Y1(0);
|
||||||
|
|
||||||
|
// erase lower-right coordinate
|
||||||
|
vdp1.reg.EWRR = EWRR__16BPP_X3(319) | EWRR__Y3(239);
|
||||||
|
|
||||||
|
vdp1.vram.cmd[0].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__SYSTEM_CLIP_COORDINATES;
|
||||||
|
vdp1.vram.cmd[0].LINK = 0;
|
||||||
|
vdp1.vram.cmd[0].XC = 319;
|
||||||
|
vdp1.vram.cmd[0].YC = 239;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[1].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__LOCAL_COORDINATE;
|
||||||
|
vdp1.vram.cmd[1].LINK = 0;
|
||||||
|
vdp1.vram.cmd[1].XA = 0;
|
||||||
|
vdp1.vram.cmd[1].YA = 0;
|
||||||
|
|
||||||
|
vdp1.vram.cmd[2].CTRL = CTRL__END;
|
||||||
|
|
||||||
|
draw_state.cmd_ix = 2;
|
||||||
|
|
||||||
|
// start drawing (execute the command list) on every frame
|
||||||
|
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint32_t n, uint32_t size>
|
||||||
|
inline void draw_label(const uint8_t(&label)[size], int32_t advance, int32_t & row, uint32_t value)
|
||||||
|
{
|
||||||
|
advance = (advance * 8) << 6;
|
||||||
|
advance += draw_string(label, (sizeof (label)) - 1, advance, row);
|
||||||
|
uint8_t v[n];
|
||||||
|
print_hex(v, (sizeof (v)), value);
|
||||||
|
draw_string(v, (sizeof (v)), advance, row);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void render()
|
||||||
|
{
|
||||||
|
draw_state.cmd_ix = 2;
|
||||||
|
|
||||||
|
if ((scsp.ram.u32[0] & 0xffff0000) != static_cast<uint32_t>(0xdead << 16))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint16_t slot_ix = scsp.ram.u32[0] & 0xffff;
|
||||||
|
uint16_t slotp_ix = (slot_ix - 1) & 31;
|
||||||
|
slot_ix &= 31;
|
||||||
|
uint32_t frame = scsp.ram.u32[1];
|
||||||
|
|
||||||
|
int32_t row = 1;
|
||||||
|
|
||||||
|
const uint8_t frame_l[] = "frame: 0x";
|
||||||
|
draw_label<4>(frame_l, 1, row, frame);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
|
||||||
|
// previous slot
|
||||||
|
const uint8_t slotp_l[] = "slot_previous: 0x";
|
||||||
|
draw_label<2>(slotp_l, 1, row, slotp_ix);
|
||||||
|
|
||||||
|
scsp_slot& slot_p = scsp.reg.slot[slotp_ix];
|
||||||
|
|
||||||
|
const uint8_t kyonb_l[] = "KYONB: ";
|
||||||
|
const uint32_t kyonb_p = (slot_p.LOOP >> 11) & 1;
|
||||||
|
draw_label<1>(kyonb_l, 3, row, kyonb_p);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
|
||||||
|
// current slot
|
||||||
|
const uint8_t slot_l[] = "slot: 0x";
|
||||||
|
draw_label<2>(slot_l, 1, row, slot_ix);
|
||||||
|
|
||||||
|
scsp_slot& slot = scsp.reg.slot[slot_ix];
|
||||||
|
|
||||||
|
uint32_t kyonb = (slot.LOOP >> 11) & 1;
|
||||||
|
draw_label<1>(kyonb_l, 3, row, kyonb);
|
||||||
|
|
||||||
|
const uint8_t sa_l[] = "SA: 0x";
|
||||||
|
const uint32_t sa = ((slot.LOOP & 0b1111) << 16) | slot.SA;
|
||||||
|
draw_label<5>(sa_l, 3, row, sa);
|
||||||
|
|
||||||
|
const uint8_t lsa_l[] = "LSA: 0x";
|
||||||
|
draw_label<4>(lsa_l, 3, row, slot.LSA);
|
||||||
|
|
||||||
|
const uint8_t lea_l[] = "LEA: 0x";
|
||||||
|
draw_label<4>(lea_l, 3, row, slot.LEA);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
|
||||||
|
// global
|
||||||
|
const uint8_t ca_l[] = "STATUS__CA: 0x";
|
||||||
|
draw_label<1>(ca_l, 1, row, STATUS__CA(scsp.reg.ctrl.STATUS));
|
||||||
|
|
||||||
|
vdp1.vram.cmd[draw_state.cmd_ix].CTRL = CTRL__END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void v_blank_in_int(void) __attribute__ ((interrupt_handler));
|
||||||
|
void v_blank_in_int()
|
||||||
|
{
|
||||||
|
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
||||||
|
scu.reg.IMS = ~(IMS__V_BLANK_IN);
|
||||||
|
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
uint32_t top = (sizeof (union vdp1_vram));
|
||||||
|
top = init_font(top);
|
||||||
|
|
||||||
|
init_vdp();
|
||||||
|
|
||||||
|
sh2_vec[SCU_VEC__V_BLANK_IN] = (u32)(&v_blank_in_int);
|
||||||
|
|
||||||
|
scu.reg.IST = 0;
|
||||||
|
scu.reg.IMS = ~(IMS__V_BLANK_IN);
|
||||||
|
|
||||||
|
init_sound();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
@ -15,23 +15,32 @@ void main()
|
|||||||
The document suggests that Sound RAM is (somewhat) preserved
|
The document suggests that Sound RAM is (somewhat) preserved
|
||||||
during SNDOFF.
|
during SNDOFF.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while ((smpc.reg.SF & 1) != 0);
|
while ((smpc.reg.SF & 1) != 0);
|
||||||
smpc.reg.SF = 1;
|
smpc.reg.SF = 1;
|
||||||
smpc.reg.COMREG = COMREG__SNDOFF;
|
smpc.reg.COMREG = COMREG__SNDOFF;
|
||||||
while (smpc.reg.oreg[31] != OREG31__SNDOFF);
|
while (smpc.reg.oreg[31] != OREG31__SNDOFF);
|
||||||
|
|
||||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB;
|
scsp.reg.ctrl.MIXER = MIXER__MEM4MB;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The Saturn BIOS does not (un)initialize the DSP. Without zeroizing the DSP
|
||||||
|
program, the SCSP DSP appears to have a program that continuously writes to
|
||||||
|
0x30000 through 0x3ffff in sound RAM, which has the effect of destroying any
|
||||||
|
samples stored there.
|
||||||
|
*/
|
||||||
|
reg32 * dsp_steps = reinterpret_cast<reg32*>(&(scsp.reg.dsp.STEP[0].MPRO[0]));
|
||||||
|
fill<reg32>(dsp_steps, 0, (sizeof (scsp.reg.dsp.STEP)));
|
||||||
|
|
||||||
uint32_t * m68k_main_start = reinterpret_cast<uint32_t*>(&_m68k_start);
|
uint32_t * m68k_main_start = reinterpret_cast<uint32_t*>(&_m68k_start);
|
||||||
uint32_t m68k_main_size = reinterpret_cast<uint32_t>(&_m68k_size);
|
uint32_t m68k_main_size = reinterpret_cast<uint32_t>(&_m68k_size);
|
||||||
copy<uint32_t>(&scsp.ram.u32[0], m68k_main_start, m68k_main_size);
|
copy<uint32_t>(&scsp.ram.u32[0], m68k_main_start, m68k_main_size);
|
||||||
|
|
||||||
while ((smpc.reg.SF & 1) != 0);
|
while ((smpc.reg.SF & 1) != 0);
|
||||||
smpc.reg.SF = 1;
|
smpc.reg.SF = 1;
|
||||||
smpc.reg.COMREG = COMREG__SNDON;
|
smpc.reg.COMREG = COMREG__SNDON;
|
||||||
while (smpc.reg.oreg[31] != OREG31__SNDON);
|
while (smpc.reg.oreg[31] != OREG31__SNDON);
|
||||||
|
|
||||||
// do nothing while the sound CPU manipulates the SCSP
|
// do nothing while the sound CPU manipulates the SCSP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|||||||
#if defined __vxworks && defined __PIC__
|
#if defined __vxworks && defined __PIC__
|
||||||
#define NO_FPSCR_VALUES
|
#define NO_FPSCR_VALUES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef L_ashiftrt
|
#ifdef L_ashiftrt
|
||||||
.global GLOBAL(ashiftrt_r4_0)
|
.global GLOBAL(ashiftrt_r4_0)
|
||||||
.global GLOBAL(ashiftrt_r4_1)
|
.global GLOBAL(ashiftrt_r4_1)
|
||||||
@ -552,7 +552,7 @@ LOCAL(ashlsi_29):
|
|||||||
LOCAL(ashlsi_30):
|
LOCAL(ashlsi_30):
|
||||||
shlr2 r0
|
shlr2 r0
|
||||||
rts
|
rts
|
||||||
shll16 r0
|
shll16 r0
|
||||||
|
|
||||||
ENDFUNC(GLOBAL(ashlsi3))
|
ENDFUNC(GLOBAL(ashlsi3))
|
||||||
ENDFUNC(GLOBAL(ashlsi3_r0))
|
ENDFUNC(GLOBAL(ashlsi3_r0))
|
||||||
@ -728,7 +728,7 @@ LOCAL(lshrsi_29):
|
|||||||
LOCAL(lshrsi_30):
|
LOCAL(lshrsi_30):
|
||||||
shll2 r0
|
shll2 r0
|
||||||
rts
|
rts
|
||||||
shlr16 r0
|
shlr16 r0
|
||||||
|
|
||||||
ENDFUNC(GLOBAL(lshrsi3))
|
ENDFUNC(GLOBAL(lshrsi3))
|
||||||
ENDFUNC(GLOBAL(lshrsi3_r0))
|
ENDFUNC(GLOBAL(lshrsi3_r0))
|
||||||
@ -1063,7 +1063,7 @@ GLOBAL(sdivsi3_i4):
|
|||||||
fdiv dr2,dr0
|
fdiv dr2,dr0
|
||||||
ftrc dr0,fpul
|
ftrc dr0,fpul
|
||||||
rts
|
rts
|
||||||
fpchg
|
fpchg
|
||||||
|
|
||||||
#endif /* __SH4A__ */
|
#endif /* __SH4A__ */
|
||||||
|
|
||||||
@ -1722,7 +1722,7 @@ LOCAL(div_ge64k_2):
|
|||||||
and r1,r0
|
and r1,r0
|
||||||
bra LOCAL(div_ge64k_end)
|
bra LOCAL(div_ge64k_end)
|
||||||
xor r4,r0
|
xor r4,r0
|
||||||
|
|
||||||
LOCAL(div_r8):
|
LOCAL(div_r8):
|
||||||
shll16 r4
|
shll16 r4
|
||||||
bra LOCAL(div_r8_2)
|
bra LOCAL(div_r8_2)
|
||||||
@ -2257,7 +2257,7 @@ GLOBAL(udiv_qrnnd_16):
|
|||||||
cmp/hi r6,r0
|
cmp/hi r6,r0
|
||||||
bt .Lots
|
bt .Lots
|
||||||
.rept 16
|
.rept 16
|
||||||
div1 r6,r0
|
div1 r6,r0
|
||||||
.endr
|
.endr
|
||||||
extu.w r0,r1
|
extu.w r0,r1
|
||||||
bt 0f
|
bt 0f
|
||||||
|
@ -10,6 +10,11 @@ all: ttf-convert
|
|||||||
%: %.o
|
%: %.o
|
||||||
$(CXX) $(LDFLAGS) $< -o $@
|
$(CXX) $(LDFLAGS) $< -o $@
|
||||||
|
|
||||||
.SUFFIXES:
|
clean:
|
||||||
|
rm -f *.o ttf-convert
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.INTERMEDIATE:
|
||||||
|
.SECONDARY:
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
# /usr/share/fonts/OTF/ipagp.ttf
|
|
||||||
|
@ -68,7 +68,7 @@ load_outline_char(const FT_Face face,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE);
|
//assert(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE);
|
||||||
|
|
||||||
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
|
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -79,6 +79,8 @@ load_outline_char(const FT_Face face,
|
|||||||
uint32_t pitch = (face->glyph->bitmap.pitch + 8 - 1) & -8;
|
uint32_t pitch = (face->glyph->bitmap.pitch + 8 - 1) & -8;
|
||||||
uint32_t bitmap_size = face->glyph->bitmap.rows * pitch;
|
uint32_t bitmap_size = face->glyph->bitmap.rows * pitch;
|
||||||
|
|
||||||
|
//printf("num_grays %d\n", face->glyph->bitmap.num_grays);
|
||||||
|
|
||||||
if (!(face->glyph->bitmap.pitch > 0)) {
|
if (!(face->glyph->bitmap.pitch > 0)) {
|
||||||
assert(pitch == 0);
|
assert(pitch == 0);
|
||||||
assert(bitmap_size == 0);
|
assert(bitmap_size == 0);
|
||||||
@ -86,11 +88,41 @@ load_outline_char(const FT_Face face,
|
|||||||
assert(face->glyph->bitmap.rows == 0);
|
assert(face->glyph->bitmap.rows == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t y = 0; y < face->glyph->bitmap.rows; y++) {
|
switch (face->glyph->bitmap.num_grays) {
|
||||||
for (uint32_t x = 0; x < face->glyph->bitmap.width; x++) {
|
case 2:
|
||||||
uint8_t i = face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch + x];
|
{
|
||||||
glyph_bitmaps[bitmap_offset + (y * pitch + x)] = i >> 3;
|
for (unsigned int y = 0; y < face->glyph->bitmap.rows; y++) {
|
||||||
|
uint8_t * row = &face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch];
|
||||||
|
//uint8_t row_out = 0;
|
||||||
|
for (unsigned int x = 0; x < face->glyph->bitmap.width; x++) {
|
||||||
|
int bit;
|
||||||
|
bit = (row[x / 8] >> (7 - (x % 8))) & 1;
|
||||||
|
//fprintf(stderr, bit ? "█" : " ");
|
||||||
|
//row_out |= (bit << x);
|
||||||
|
|
||||||
|
// FIXME: this is lazy: this bloats the storage format from
|
||||||
|
// 1 bit per pixel to 8 bits per pixel, even though this
|
||||||
|
// expansion could be done at runtime inside vdp1 vram
|
||||||
|
// instead.
|
||||||
|
glyph_bitmaps[bitmap_offset + (y * pitch + x)] = bit ? 31 : 0;
|
||||||
|
}
|
||||||
|
//fprintf(stderr, "\n");
|
||||||
|
//buf[y] = row_out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 256:
|
||||||
|
{
|
||||||
|
for (uint32_t y = 0; y < face->glyph->bitmap.rows; y++) {
|
||||||
|
for (uint32_t x = 0; x < face->glyph->bitmap.width; x++) {
|
||||||
|
uint8_t i = face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch + x];
|
||||||
|
glyph_bitmaps[bitmap_offset + (y * pitch + x)] = i >> 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(-1 == face->glyph->bitmap.num_grays);
|
||||||
}
|
}
|
||||||
|
|
||||||
//memcpy(&glyph_bitmaps[bitmap_offset], face->glyph->bitmap.buffer, bitmap_size);
|
//memcpy(&glyph_bitmaps[bitmap_offset], face->glyph->bitmap.buffer, bitmap_size);
|
||||||
@ -130,7 +162,7 @@ int main(int argc, char *argv[])
|
|||||||
FT_Face face;
|
FT_Face face;
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
|
||||||
if (argc < 5) {
|
if (argc != 6) {
|
||||||
std::cerr << "usage: " << argv[0] << " [start-hex] [end-hex] [pixel-size] [font-file-path] [output-file-path]\n\n";
|
std::cerr << "usage: " << argv[0] << " [start-hex] [end-hex] [pixel-size] [font-file-path] [output-file-path]\n\n";
|
||||||
std::cerr << " ex: " << argv[0] << " 3000 30ff 30 ipagp.ttf font.bin\n";
|
std::cerr << " ex: " << argv[0] << " 3000 30ff 30 ipagp.ttf font.bin\n";
|
||||||
return -1;
|
return -1;
|
||||||
@ -178,9 +210,6 @@ int main(int argc, char *argv[])
|
|||||||
ss2 << std::hex << argv[2];
|
ss2 << std::hex << argv[2];
|
||||||
ss2 >> end;
|
ss2 >> end;
|
||||||
|
|
||||||
//uint32_t start = 0x20;
|
|
||||||
//uint32_t end = 0x7f;
|
|
||||||
|
|
||||||
glyph glyphs[(end - start) + 1];
|
glyph glyphs[(end - start) + 1];
|
||||||
uint8_t glyph_bitmaps[1024 * 1024];
|
uint8_t glyph_bitmaps[1024 * 1024];
|
||||||
memset(glyph_bitmaps, 0x00, 1024 * 1024);
|
memset(glyph_bitmaps, 0x00, 1024 * 1024);
|
||||||
@ -218,6 +247,10 @@ int main(int argc, char *argv[])
|
|||||||
std::cerr << "glyph_index: 0x" << std::hex << glyph_index << '\n';
|
std::cerr << "glyph_index: 0x" << std::hex << glyph_index << '\n';
|
||||||
|
|
||||||
FILE * out = fopen(argv[5], "w");
|
FILE * out = fopen(argv[5], "w");
|
||||||
|
if (out == NULL) {
|
||||||
|
perror("fopen(w)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
fwrite(reinterpret_cast<void*>(&font), (sizeof (font)), 1, out);
|
fwrite(reinterpret_cast<void*>(&font), (sizeof (font)), 1, out);
|
||||||
fwrite(reinterpret_cast<void*>(&glyphs[0]), (sizeof (glyph)), glyph_index, out);
|
fwrite(reinterpret_cast<void*>(&glyphs[0]), (sizeof (glyph)), glyph_index, out);
|
||||||
|
@ -203,7 +203,8 @@ void render()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void v_blank_in_int(void) __attribute__ ((interrupt_handler));
|
void v_blank_in_int(void) __attribute__ ((interrupt_handler));
|
||||||
void v_blank_in_int() {
|
void v_blank_in_int()
|
||||||
|
{
|
||||||
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
scu.reg.IST &= ~(IST__V_BLANK_IN);
|
||||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||||
|
|
||||||
@ -262,14 +263,14 @@ void main()
|
|||||||
uint32_t top = (sizeof (union vdp1_vram));
|
uint32_t top = (sizeof (union vdp1_vram));
|
||||||
top = init_font(top);
|
top = init_font(top);
|
||||||
|
|
||||||
// wait for the beginning of a V blank
|
|
||||||
v_blank_in();
|
|
||||||
|
|
||||||
// wordle init
|
// wordle init
|
||||||
const uint8_t word_ix = 6;
|
const uint8_t word_ix = 6;
|
||||||
wordle::init_screen(wordle_state, word_ix);
|
wordle::init_screen(wordle_state, word_ix);
|
||||||
// end wordle init
|
// end wordle init
|
||||||
|
|
||||||
|
// wait for the beginning of a V blank
|
||||||
|
v_blank_in();
|
||||||
|
|
||||||
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
// DISP: Please make sure to change this bit from 0 to 1 during V blank.
|
||||||
vdp2.reg.TVMD = ( TVMD__DISP | TVMD__LSMD__NON_INTERLACE
|
vdp2.reg.TVMD = ( TVMD__DISP | TVMD__LSMD__NON_INTERLACE
|
||||||
| TVMD__VRESO__240 | TVMD__HRESO__NORMAL_320);
|
| TVMD__VRESO__240 | TVMD__HRESO__NORMAL_320);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user