scsp: add fm example
This commit is contained in:
parent
5ee43d8a29
commit
f7a178384c
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@
|
||||
*.ppm
|
||||
*.png
|
||||
*.out
|
||||
*.pcm
|
||||
res/mai.data
|
||||
tools/ttf-convert
|
||||
tools/ttf-bitmap
|
||||
|
15
Makefile
15
Makefile
@ -92,14 +92,23 @@ wordle/wordle.o: wordle/word_list.hpp
|
||||
|
||||
wordle/wordle.elf: wordle/main_saturn.o wordle/wordle.o wordle/draw.o sh/lib1funcs.o res/dejavusansmono.font.bin.o common/keyboard.o common/draw_font.o common/palette.o
|
||||
|
||||
scsp/sine-44100-s16be-1ch.pcm:
|
||||
# 88200 bytes
|
||||
scsp/sine-44100-s16be-1ch-1sec.pcm:
|
||||
sox \
|
||||
-r 44100 -e signed-integer -b 16 -c 1 -n -B \
|
||||
$@.raw \
|
||||
synth 1 sin 440 vol -10dB
|
||||
mv $@.raw $@
|
||||
|
||||
scsp/slot.elf: scsp/slot.o scsp/sine-44100-s16be-1ch.pcm.o
|
||||
# 200 bytes
|
||||
scsp/sine-44100-s16be-1ch-100sample.pcm:
|
||||
sox \
|
||||
-r 44100 -e signed-integer -b 16 -c 1 -n -B \
|
||||
$@.raw \
|
||||
synth 100s sin 440 vol -10dB
|
||||
mv $@.raw $@
|
||||
|
||||
scsp/slot.elf: scsp/slot.o scsp/sine-44100-s16be-1ch-1sec.pcm.o
|
||||
|
||||
m68k:
|
||||
|
||||
@ -110,6 +119,8 @@ 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 sh/lib1funcs.o res/sperrypc.font.bin.o common/draw_font.o common/palette.o
|
||||
|
||||
scsp/fm.elf: scsp/fm.o res/nec.bitmap.bin.o sh/lib1funcs.o saturn/start.o scsp/sine-44100-s16be-1ch-100sample.pcm.o
|
||||
|
||||
res/sperrypc.bitmap.bin: tools/ttf-bitmap
|
||||
./tools/ttf-bitmap 20 7f res/Bm437_SperryPC_CGA.otb $@
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace intback {
|
||||
enum intback_fsm {
|
||||
enum fsm : uint8_t {
|
||||
PORT_STATUS = 0,
|
||||
PERIPHERAL_ID,
|
||||
DATA1,
|
||||
@ -9,7 +11,7 @@ namespace intback {
|
||||
FSM_NEXT
|
||||
};
|
||||
|
||||
struct intback_state {
|
||||
struct state {
|
||||
uint8_t fsm;
|
||||
uint8_t controller_ix;
|
||||
uint8_t port_ix;
|
||||
@ -21,11 +23,12 @@ namespace intback {
|
||||
uint8_t kbd_bits;
|
||||
};
|
||||
|
||||
typedef void (*keyboard_func_ptr)(const enum keysym k, uint8_t kbd_bits);
|
||||
typedef void (*keyboard_func_ptr)(uint8_t keysym, uint8_t kbd_bits);
|
||||
typedef void (*digital_func_ptr)(uint8_t fsm_state, uint8_t data);
|
||||
|
||||
static intback_state state;
|
||||
static struct state state;
|
||||
|
||||
inline void keyboard_fsm(keyboard_func_ptr callback)
|
||||
inline void fsm(digital_func_ptr digital_cb, keyboard_func_ptr keyboard_cb)
|
||||
{
|
||||
if ((smpc.reg.SR & SR__PDL) != 0) {
|
||||
// PDL == 1; 1st peripheral data
|
||||
@ -65,18 +68,16 @@ namespace intback {
|
||||
state.data_size = PERIPHERAL_ID__DATA_SIZE(oreg);
|
||||
break;
|
||||
case DATA1:
|
||||
if (digital_cb != nullptr) digital_cb(state.fsm, oreg);
|
||||
break;
|
||||
case DATA2:
|
||||
if (digital_cb != nullptr) digital_cb(state.fsm, oreg);
|
||||
break;
|
||||
case DATA3:
|
||||
state.kbd_bits = oreg & 0b1111;
|
||||
break;
|
||||
case DATA4:
|
||||
{
|
||||
uint32_t keysym = oreg;
|
||||
enum keysym k = scancode_to_keysym(keysym);
|
||||
callback(k, state.kbd_bits);
|
||||
}
|
||||
if (keyboard_cb != nullptr) keyboard_cb(state.kbd_bits, oreg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
21
common/string.hpp
Normal file
21
common/string.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace string {
|
||||
template <typename T>
|
||||
inline void hex(T * c, uint32_t len, uint32_t n)
|
||||
{
|
||||
while (len > 0) {
|
||||
uint32_t nib = n & 0xf;
|
||||
n = n >> 4;
|
||||
if (nib > 9) {
|
||||
nib += (97 - 10);
|
||||
} else {
|
||||
nib += (48 - 0);
|
||||
}
|
||||
|
||||
c[--len] = nib;
|
||||
}
|
||||
}
|
||||
}
|
@ -166,8 +166,10 @@ inline void keyboard_regular_key(const enum keysym k)
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard_callback(const enum keysym k, uint8_t kbd_bits)
|
||||
void keyboard_callback(uint8_t kbd_bits, uint8_t scancode)
|
||||
{
|
||||
enum keysym k = scancode_to_keysym(scancode);
|
||||
|
||||
if (KEYBOARD__MAKE(kbd_bits)) {
|
||||
switch (k) {
|
||||
case keysym::LEFT_SHIFT : modifier_state |= MODIFIER_LEFT_SHIFT; break;
|
||||
@ -200,7 +202,7 @@ void smpc_int(void)
|
||||
scu.reg.IST &= ~(IST__SMPC);
|
||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||
|
||||
intback::keyboard_fsm(keyboard_callback);
|
||||
intback::fsm(nullptr, keyboard_callback);
|
||||
}
|
||||
|
||||
constexpr int32_t plane_a = 2;
|
||||
|
@ -9,6 +9,6 @@ include $(LIB)/m68k/common.mk
|
||||
%.pcm.o: %.pcm
|
||||
$(BUILD_BINARY_O)
|
||||
|
||||
slot.elf: slot.o sine-44100-s16be-1ch.pcm.o
|
||||
slot.elf: slot.o sine-44100-s16be-1ch-1sec.pcm.o
|
||||
|
||||
interrupt.elf: interrupt.o jojo-11025-s16be-1ch.pcm.o
|
||||
|
@ -37,8 +37,7 @@ void auto_vector_1(void)
|
||||
slot.LSA = 0; // loop start address (samples)
|
||||
slot.LEA = frame_size; // 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.FM = 0; // stwinh sdir tl 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
|
||||
@ -63,8 +62,7 @@ void main()
|
||||
slot.LSA = 0;
|
||||
slot.LEA = 0;
|
||||
slot.EG = 0;
|
||||
slot.VOLUME = 0;
|
||||
slot.FM = 0;
|
||||
slot.FM = 0; // 32-bit access
|
||||
slot.PITCH = 0;
|
||||
slot.LFO = 0;
|
||||
slot.MIXER = 0;
|
||||
|
@ -21,8 +21,7 @@ void main()
|
||||
slot.LSA = 0; // loop start address (samples)
|
||||
slot.LEA = 44100; // 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.FM = 0; // stwinh sdir tl mdl mdxsl mdysl
|
||||
slot.PITCH = PITCH__OCT(0) | PITCH__FNS(0); // oct fns
|
||||
slot.LFO = 0; // lfof plfows
|
||||
slot.MIXER = MIXER__DISDL(0b101); // disdl dipan efsdl efpan
|
||||
|
753
scsp/fm.cpp
Normal file
753
scsp/fm.cpp
Normal file
@ -0,0 +1,753 @@
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "vdp2.h"
|
||||
#include "smpc.h"
|
||||
#include "scu.h"
|
||||
#include "sh2.h"
|
||||
#include "scsp.h"
|
||||
|
||||
#include "../common/copy.hpp"
|
||||
#include "../common/intback.hpp"
|
||||
#include "../common/vdp2_func.hpp"
|
||||
#include "../common/string.hpp"
|
||||
|
||||
extern void * _sine_start __asm("_binary_scsp_sine_44100_s16be_1ch_100sample_pcm_start");
|
||||
extern void * _sine_size __asm("_binary_scsp_sine_44100_s16be_1ch_100sample_pcm_size");
|
||||
|
||||
struct mask_bit {
|
||||
uint32_t mask;
|
||||
uint32_t bit;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr inline std::remove_volatile_t<typename T::reg_type> get(const typename T::reg_type r)
|
||||
{
|
||||
return (r >> T::bit) & T::mask;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline void set(typename T::reg_type& r, uint32_t n)
|
||||
{
|
||||
r = (r & ~(T::mask << T::bit)) | ((n & T::mask) << T::bit);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline void incdec(typename T::reg_type& r, int32_t n)
|
||||
{
|
||||
int32_t ni = static_cast<int32_t>(get<T>(r)) + n;
|
||||
set<T>(r, ni);
|
||||
}
|
||||
|
||||
|
||||
#define BITS(N, T, M, B) \
|
||||
struct N { using reg_type = T; \
|
||||
static constexpr uint32_t mask = M; \
|
||||
static constexpr uint32_t bit = B; }
|
||||
|
||||
namespace loop {
|
||||
BITS(kyonex, reg16, 0b1, 12);
|
||||
BITS(kyonb, reg16, 0b1, 11);
|
||||
BITS(sbctl, reg16, 0b11, 9);
|
||||
BITS(ssctl, reg16, 0b11, 7);
|
||||
BITS(lpctl, reg16, 0b11, 5);
|
||||
BITS(pcm8b, reg16, 0b1, 4);
|
||||
}
|
||||
|
||||
namespace sa {
|
||||
BITS(sa, reg32, 0xf'ffff, 0);
|
||||
}
|
||||
|
||||
namespace lsa {
|
||||
BITS(lsa, reg16, 0xffff, 0);
|
||||
}
|
||||
|
||||
namespace lea {
|
||||
BITS(lea, reg16, 0xffff, 0);
|
||||
}
|
||||
|
||||
namespace eg {
|
||||
BITS(d2r, reg32, 0x1f, 11 + 16);
|
||||
BITS(d1r, reg32, 0x1f, 6 + 16);
|
||||
BITS(eghold, reg32, 0b1, 5 + 16);
|
||||
BITS(ar, reg32, 0x1f, 0 + 16);
|
||||
BITS(lpslnk, reg32, 0b1, 14);
|
||||
BITS(krs, reg32, 0xf, 10);
|
||||
BITS(dl, reg32, 0x1f, 5);
|
||||
BITS(rr, reg32, 0x1f, 0);
|
||||
}
|
||||
|
||||
namespace fm {
|
||||
BITS(stwinh, reg32, 0b1, 9 + 16);
|
||||
BITS(sdir, reg32, 0b1, 8 + 16);
|
||||
BITS(tl, reg32, 0xff, 0 + 16);
|
||||
BITS(mdl, reg32, 0xf, 12);
|
||||
BITS(mdxsl, reg32, 0x3f, 6);
|
||||
BITS(mdysl, reg32, 0x3f, 0);
|
||||
}
|
||||
|
||||
namespace pitch {
|
||||
BITS(oct, reg16, 0xf, 11);
|
||||
BITS(fns, reg16, 0x3ff, 0);
|
||||
}
|
||||
|
||||
namespace lfo {
|
||||
BITS(lfore, reg16, 0b1, 15);
|
||||
BITS(lfof, reg16, 0x1f, 10);
|
||||
BITS(plfows, reg16, 0b11, 8);
|
||||
BITS(plfos, reg16, 0b111, 5);
|
||||
BITS(alfows, reg16, 0b11, 3);
|
||||
BITS(alfos, reg16, 0b111, 0);
|
||||
}
|
||||
|
||||
namespace mixer {
|
||||
BITS(isel, reg32, 0b1111, 3 + 16);
|
||||
BITS(imxl, reg32, 0b111, 0 + 16);
|
||||
BITS(disdl, reg32, 0b111, 13);
|
||||
BITS(dipan, reg32, 0b11111, 8);
|
||||
BITS(efsdl, reg32, 0b111, 5);
|
||||
BITS(efpan, reg32, 0b11111, 0);
|
||||
}
|
||||
|
||||
enum class scsp_name : uint8_t {
|
||||
kyonex,
|
||||
kyonb,
|
||||
sbctl,
|
||||
ssctl,
|
||||
lpctl,
|
||||
pcm8b,
|
||||
|
||||
sa,
|
||||
|
||||
lsa,
|
||||
|
||||
lea,
|
||||
|
||||
d2r,
|
||||
d1r,
|
||||
eghold,
|
||||
ar,
|
||||
lpslnk,
|
||||
krs,
|
||||
dl,
|
||||
rr,
|
||||
|
||||
stwinh,
|
||||
sdir,
|
||||
tl,
|
||||
mdl,
|
||||
mdxsl,
|
||||
mdysl,
|
||||
|
||||
oct,
|
||||
fns,
|
||||
|
||||
lfore,
|
||||
lfof,
|
||||
plfows,
|
||||
plfos,
|
||||
alfows,
|
||||
alfos,
|
||||
|
||||
isel,
|
||||
imxl,
|
||||
disdl,
|
||||
dipan,
|
||||
efsdl,
|
||||
efpan,
|
||||
|
||||
FIRST = kyonex,
|
||||
LAST = efpan,
|
||||
};
|
||||
|
||||
std::optional<scsp_name> grid[7][8] = {
|
||||
// 0 1 2 3 4 5 6 7
|
||||
{scsp_name::kyonex, scsp_name::kyonb, scsp_name::sbctl, std::nullopt, scsp_name::ssctl, std::nullopt, scsp_name::lpctl, scsp_name::pcm8b},
|
||||
{scsp_name::sa, std::nullopt, std::nullopt, scsp_name::lsa, std::nullopt, std::nullopt, scsp_name::lea, std::nullopt},
|
||||
{scsp_name::d2r, scsp_name::d1r, scsp_name::eghold, scsp_name::ar, scsp_name::lpslnk, scsp_name::krs, scsp_name::dl, scsp_name::rr},
|
||||
{scsp_name::stwinh, std::nullopt, scsp_name::sdir, scsp_name::tl, scsp_name::mdl, scsp_name::mdxsl, std::nullopt, scsp_name::mdysl},
|
||||
{scsp_name::oct, std::nullopt, std::nullopt, std::nullopt, scsp_name::fns, std::nullopt, std::nullopt, std::nullopt},
|
||||
{scsp_name::lfore, scsp_name::lfof, scsp_name::plfows, std::nullopt, scsp_name::plfos, scsp_name::alfows, std::nullopt, scsp_name::alfos},
|
||||
{scsp_name::isel, scsp_name::imxl, std::nullopt, scsp_name::disdl, scsp_name::dipan, scsp_name::efsdl, std::nullopt, scsp_name::efpan},
|
||||
};
|
||||
|
||||
uint32_t get_reg(scsp_slot& slot, scsp_name reg_name)
|
||||
{
|
||||
switch (reg_name) {
|
||||
case scsp_name::kyonex: return get<loop::kyonex>(slot.LOOP); break;
|
||||
case scsp_name::kyonb: return get<loop::kyonb >(slot.LOOP); break;
|
||||
case scsp_name::sbctl: return get<loop::sbctl >(slot.LOOP); break;
|
||||
case scsp_name::ssctl: return get<loop::ssctl >(slot.LOOP); break;
|
||||
case scsp_name::lpctl: return get<loop::lpctl >(slot.LOOP); break;
|
||||
case scsp_name::pcm8b: return get<loop::pcm8b >(slot.LOOP); break;
|
||||
|
||||
case scsp_name::sa: return get<sa::sa >(slot.SA); break;
|
||||
|
||||
case scsp_name::lsa: return get<lsa::lsa>(slot.LSA); break;
|
||||
|
||||
case scsp_name::lea: return get<lea::lea>(slot.LEA); break;
|
||||
|
||||
case scsp_name::d2r: return get<eg::d2r >(slot.EG); break;
|
||||
case scsp_name::d1r: return get<eg::d1r >(slot.EG); break;
|
||||
case scsp_name::eghold: return get<eg::eghold>(slot.EG); break;
|
||||
case scsp_name::ar: return get<eg::ar >(slot.EG); break;
|
||||
case scsp_name::lpslnk: return get<eg::lpslnk>(slot.EG); break;
|
||||
case scsp_name::krs: return get<eg::krs >(slot.EG); break;
|
||||
case scsp_name::dl: return get<eg::dl >(slot.EG); break;
|
||||
case scsp_name::rr: return get<eg::rr >(slot.EG); break;
|
||||
|
||||
case scsp_name::stwinh: return get<fm::stwinh>(slot.FM); break;
|
||||
case scsp_name::sdir: return get<fm::sdir >(slot.FM); break;
|
||||
case scsp_name::tl: return get<fm::tl >(slot.FM); break;
|
||||
case scsp_name::mdl: return get<fm::mdl >(slot.FM); break;
|
||||
case scsp_name::mdxsl: return get<fm::mdxsl >(slot.FM); break;
|
||||
case scsp_name::mdysl: return get<fm::mdysl >(slot.FM); break;
|
||||
|
||||
case scsp_name::oct: return get<pitch::oct>(slot.PITCH); break;
|
||||
case scsp_name::fns: return get<pitch::fns>(slot.PITCH); break;
|
||||
|
||||
case scsp_name::lfore: return get<lfo::lfore >(slot.LFO); break;
|
||||
case scsp_name::lfof: return get<lfo::lfof >(slot.LFO); break;
|
||||
case scsp_name::plfows: return get<lfo::plfows>(slot.LFO); break;
|
||||
case scsp_name::plfos: return get<lfo::plfos >(slot.LFO); break;
|
||||
case scsp_name::alfows: return get<lfo::alfows>(slot.LFO); break;
|
||||
case scsp_name::alfos: return get<lfo::alfos >(slot.LFO); break;
|
||||
|
||||
case scsp_name::isel: return get<mixer::isel >(slot.MIXER); break;
|
||||
case scsp_name::imxl: return get<mixer::imxl >(slot.MIXER); break;
|
||||
case scsp_name::disdl: return get<mixer::disdl>(slot.MIXER); break;
|
||||
case scsp_name::dipan: return get<mixer::dipan>(slot.MIXER); break;
|
||||
case scsp_name::efsdl: return get<mixer::efsdl>(slot.MIXER); break;
|
||||
case scsp_name::efpan: return get<mixer::efpan>(slot.MIXER); break;
|
||||
}
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
void incdec_reg(scsp_slot& slot, scsp_name reg_name, int32_t dir)
|
||||
{
|
||||
switch (reg_name) {
|
||||
case scsp_name::kyonex: return set<loop::kyonex>(slot.LOOP, 1); break;
|
||||
case scsp_name::kyonb: return incdec<loop::kyonb >(slot.LOOP, dir); break;
|
||||
case scsp_name::sbctl: return incdec<loop::sbctl >(slot.LOOP, dir); break;
|
||||
case scsp_name::ssctl: return incdec<loop::ssctl >(slot.LOOP, dir); break;
|
||||
case scsp_name::lpctl: return incdec<loop::lpctl >(slot.LOOP, dir); break;
|
||||
case scsp_name::pcm8b: return incdec<loop::pcm8b >(slot.LOOP, dir); break;
|
||||
|
||||
case scsp_name::sa: return incdec<sa::sa >(slot.SA, dir); break;
|
||||
|
||||
case scsp_name::lsa: return incdec<lsa::lsa>(slot.LSA, dir); break;
|
||||
|
||||
case scsp_name::lea: return incdec<lea::lea>(slot.LEA, dir); break;
|
||||
|
||||
case scsp_name::d2r: return incdec<eg::d2r >(slot.EG, dir); break;
|
||||
case scsp_name::d1r: return incdec<eg::d1r >(slot.EG, dir); break;
|
||||
case scsp_name::eghold: return incdec<eg::eghold>(slot.EG, dir); break;
|
||||
case scsp_name::ar: return incdec<eg::ar >(slot.EG, dir); break;
|
||||
case scsp_name::lpslnk: return incdec<eg::lpslnk>(slot.EG, dir); break;
|
||||
case scsp_name::krs: return incdec<eg::krs >(slot.EG, dir); break;
|
||||
case scsp_name::dl: return incdec<eg::dl >(slot.EG, dir); break;
|
||||
case scsp_name::rr: return incdec<eg::rr >(slot.EG, dir); break;
|
||||
|
||||
case scsp_name::stwinh: return incdec<fm::stwinh>(slot.FM, dir); break;
|
||||
case scsp_name::sdir: return incdec<fm::sdir >(slot.FM, dir); break;
|
||||
case scsp_name::tl: return incdec<fm::tl >(slot.FM, dir); break;
|
||||
case scsp_name::mdl: return incdec<fm::mdl >(slot.FM, dir); break;
|
||||
case scsp_name::mdxsl: return incdec<fm::mdxsl >(slot.FM, dir); break;
|
||||
case scsp_name::mdysl: return incdec<fm::mdysl >(slot.FM, dir); break;
|
||||
|
||||
case scsp_name::oct: return incdec<pitch::oct>(slot.PITCH, dir); break;
|
||||
case scsp_name::fns: return incdec<pitch::fns>(slot.PITCH, dir); break;
|
||||
|
||||
case scsp_name::lfore: return incdec<lfo::lfore >(slot.LFO, dir); break;
|
||||
case scsp_name::lfof: return incdec<lfo::lfof >(slot.LFO, dir); break;
|
||||
case scsp_name::plfows: return incdec<lfo::plfows>(slot.LFO, dir); break;
|
||||
case scsp_name::plfos: return incdec<lfo::plfos >(slot.LFO, dir); break;
|
||||
case scsp_name::alfows: return incdec<lfo::alfows>(slot.LFO, dir); break;
|
||||
case scsp_name::alfos: return incdec<lfo::alfos >(slot.LFO, dir); break;
|
||||
|
||||
case scsp_name::isel: return incdec<mixer::isel >(slot.MIXER, dir); break;
|
||||
case scsp_name::imxl: return incdec<mixer::imxl >(slot.MIXER, dir); break;
|
||||
case scsp_name::disdl: return incdec<mixer::disdl>(slot.MIXER, dir); break;
|
||||
case scsp_name::dipan: return incdec<mixer::dipan>(slot.MIXER, dir); break;
|
||||
case scsp_name::efsdl: return incdec<mixer::efsdl>(slot.MIXER, dir); break;
|
||||
case scsp_name::efpan: return incdec<mixer::efpan>(slot.MIXER, dir); break;
|
||||
}
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
struct label_value {
|
||||
uint8_t name[7];
|
||||
uint8_t len;
|
||||
struct {
|
||||
int8_t y;
|
||||
int8_t x;
|
||||
} label;
|
||||
struct {
|
||||
int8_t y;
|
||||
int8_t x;
|
||||
} value;
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
constexpr typename std::underlying_type<E>::type u(E e) noexcept
|
||||
{
|
||||
return static_cast<typename std::underlying_type<E>::type>(e);
|
||||
}
|
||||
|
||||
constexpr inline int32_t clz(uint32_t v)
|
||||
{
|
||||
if (v == 0) return 32;
|
||||
int32_t n = 0;
|
||||
if ((v & 0xFFFF0000) == 0) { n = n + 16; v = v << 16; }
|
||||
if ((v & 0xFF000000) == 0) { n = n + 8; v = v << 8; }
|
||||
if ((v & 0xF0000000) == 0) { n = n + 4; v = v << 4; }
|
||||
if ((v & 0xC0000000) == 0) { n = n + 2; v = v << 2; }
|
||||
if ((v & 0x80000000) == 0) { n = n + 1; }
|
||||
return n;
|
||||
}
|
||||
|
||||
constexpr inline int32_t hl(const uint32_t v)
|
||||
{
|
||||
// return: number digits in v when represented as a base16 string
|
||||
int32_t n = 32 - clz(v);
|
||||
n = (n + 3) & ~0x03; // round up to nearest multiple of 4
|
||||
return n >> 2; // divide by 4
|
||||
}
|
||||
|
||||
label_value label_value_table[] = {
|
||||
[u(scsp_name::kyonex)] = { "KX", hl(loop::kyonex::mask), {1, 2}, {2, 2} },
|
||||
[u(scsp_name::kyonb)] = { "KB", hl(loop::kyonb::mask), {1, 7}, {2, 7} },
|
||||
[u(scsp_name::sbctl)] = { "SBCTL", hl(loop::sbctl::mask), {1, 12}, {2, 12} },
|
||||
[u(scsp_name::ssctl)] = { "SSCTL", hl(loop::ssctl::mask), {1, 20}, {2, 20} },
|
||||
[u(scsp_name::lpctl)] = { "LPCTL", hl(loop::lpctl::mask), {1, 28}, {2, 28} },
|
||||
[u(scsp_name::pcm8b)] = { "8B", hl(loop::pcm8b::mask), {1, 36}, {2, 36} },
|
||||
|
||||
[u(scsp_name::sa)] = { "SA", hl(sa::sa::mask), {4, 2}, {4, 5} },
|
||||
|
||||
[u(scsp_name::lsa)] = { "LSA", hl(lsa::lsa::mask), {4, 15}, {4, 19} },
|
||||
|
||||
[u(scsp_name::lea)] = { "LEA", hl(lea::lea::mask), {4, 28}, {4, 32} },
|
||||
|
||||
[u(scsp_name::d2r)] = { "D2R", hl(eg::d2r::mask), {6, 2}, {7, 2} },
|
||||
[u(scsp_name::d1r)] = { "D1R", hl(eg::d1r::mask), {6, 7}, {7, 7} },
|
||||
[u(scsp_name::eghold)] = { "HO", hl(eg::eghold::mask), {6, 12}, {7, 12} },
|
||||
[u(scsp_name::ar)] = { "AR", hl(eg::ar::mask), {6, 16}, {7, 16} },
|
||||
[u(scsp_name::lpslnk)] = { "LS", hl(eg::lpslnk::mask), {6, 20}, {7, 20} },
|
||||
[u(scsp_name::krs)] = { "KRS", hl(eg::krs::mask), {6, 24}, {7, 24} },
|
||||
[u(scsp_name::dl)] = { "DL", hl(eg::dl::mask), {6, 29}, {7, 29} },
|
||||
[u(scsp_name::rr)] = { "RR", hl(eg::rr::mask), {6, 33}, {7, 33} },
|
||||
|
||||
[u(scsp_name::stwinh)] = { "STWINH", hl(fm::stwinh::mask), {9, 2}, {10, 2} },
|
||||
[u(scsp_name::sdir)] = { "SDIR", hl(fm::sdir::mask), {9, 10}, {10, 10} },
|
||||
[u(scsp_name::tl)] = { "TL", hl(fm::tl::mask), {9, 16}, {10, 16} },
|
||||
[u(scsp_name::mdl)] = { "MDL", hl(fm::mdl::mask), {9, 20}, {10, 20} },
|
||||
[u(scsp_name::mdxsl)] = { "MDXSL", hl(fm::mdxsl::mask), {9, 25}, {10, 25} },
|
||||
[u(scsp_name::mdysl)] = { "MDYSL", hl(fm::mdysl::mask), {9, 32}, {10, 32} },
|
||||
|
||||
[u(scsp_name::oct)] = { "OCT", hl(pitch::oct::mask), {12, 11}, {12, 15} },
|
||||
[u(scsp_name::fns)] = { "FNS", hl(pitch::fns::mask), {12, 21}, {12, 25} },
|
||||
|
||||
[u(scsp_name::lfore)] = { "LFORE", hl(lfo::lfore::mask), {14, 2}, {15, 2} },
|
||||
[u(scsp_name::lfof)] = { "LFOF", hl(lfo::lfof::mask), {14, 8}, {15, 8} },
|
||||
[u(scsp_name::plfows)] = { "PLFOWS", hl(lfo::plfows::mask), {14, 13}, {15, 13} },
|
||||
[u(scsp_name::plfos)] = { "PLFOS", hl(lfo::plfos::mask), {14, 20}, {15, 20} },
|
||||
[u(scsp_name::alfows)] = { "ALFOWS", hl(lfo::alfows::mask), {14, 26}, {15, 26} },
|
||||
[u(scsp_name::alfos)] = { "ALFOS", hl(lfo::alfos::mask), {14, 33}, {15, 33} },
|
||||
|
||||
[u(scsp_name::isel)] = { "ISEL", hl(mixer::isel::mask), {17, 2}, {18, 2} },
|
||||
[u(scsp_name::imxl)] = { "IMXL", hl(mixer::imxl::mask), {17, 8}, {18, 8} },
|
||||
[u(scsp_name::disdl)] = { "DISDL", hl(mixer::disdl::mask), {17, 14}, {18, 14} },
|
||||
[u(scsp_name::dipan)] = { "DIPAN", hl(mixer::dipan::mask), {17, 20}, {18, 20} },
|
||||
[u(scsp_name::efsdl)] = { "EFSDL", hl(mixer::efsdl::mask), {17, 26}, {18, 26} },
|
||||
[u(scsp_name::efpan)] = { "EFPAN", hl(mixer::efpan::mask), {17, 32}, {18, 32} },
|
||||
};
|
||||
|
||||
extern void * _nec_bitmap_start __asm("_binary_res_nec_bitmap_bin_start");
|
||||
|
||||
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
|
||||
{
|
||||
return ((b & 31) << 10) | ((g & 31) << 5) | ((r & 31) << 0);
|
||||
}
|
||||
|
||||
void palette_data()
|
||||
{
|
||||
vdp2.cram.u16[1 + 0 ] = rgb15( 0, 0, 0);
|
||||
vdp2.cram.u16[2 + 0 ] = rgb15(31, 31, 31);
|
||||
|
||||
vdp2.cram.u16[1 + 16] = rgb15(31, 31, 31);
|
||||
vdp2.cram.u16[2 + 16] = rgb15( 0, 0, 0);
|
||||
|
||||
vdp2.cram.u16[1 + 32] = rgb15(10, 10, 10);
|
||||
vdp2.cram.u16[2 + 32] = rgb15(31, 31, 31);
|
||||
}
|
||||
|
||||
namespace pix_fmt_4bpp
|
||||
{
|
||||
constexpr inline uint32_t
|
||||
bit(uint8_t n, int32_t i)
|
||||
{
|
||||
i &= 7;
|
||||
auto b = (n >> (7 - i)) & 1;
|
||||
return ((b + 1) << ((7 - i) * 4));
|
||||
}
|
||||
|
||||
constexpr inline uint32_t
|
||||
bits(uint8_t n)
|
||||
{
|
||||
return
|
||||
bit(n, 0) | bit(n, 1) | bit(n, 2) | bit(n, 3)
|
||||
| bit(n, 4) | bit(n, 5) | bit(n, 6) | bit(n, 7);
|
||||
}
|
||||
|
||||
static_assert(bits(0b1100'1110) == 0x2211'2221);
|
||||
static_assert(bits(0b1010'0101) == 0x2121'1212);
|
||||
static_assert(bits(0b1000'0000) == 0x2111'1111);
|
||||
}
|
||||
|
||||
void cell_data()
|
||||
{
|
||||
const uint8_t * normal = reinterpret_cast<uint8_t*>(&_nec_bitmap_start);
|
||||
|
||||
for (int ix = 0; ix <= (0x7f - 0x20); ix++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
const uint8_t row_n = normal[ix * 8 + y];
|
||||
vdp2.vram.u32[ 0 + (ix * 8) + y] = pix_fmt_4bpp::bits(row_n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct count_flop {
|
||||
s8 count;
|
||||
u8 flop;
|
||||
u8 das;
|
||||
u8 repeat;
|
||||
};
|
||||
|
||||
struct input {
|
||||
count_flop right;
|
||||
count_flop left;
|
||||
count_flop down;
|
||||
count_flop up;
|
||||
count_flop start;
|
||||
count_flop a;
|
||||
count_flop b;
|
||||
count_flop c;
|
||||
count_flop r;
|
||||
count_flop x;
|
||||
count_flop y;
|
||||
count_flop z;
|
||||
count_flop l;
|
||||
};
|
||||
|
||||
constexpr int input_arr = 10;
|
||||
constexpr int input_das = 20;
|
||||
constexpr int input_debounce = 2;
|
||||
|
||||
static inline void
|
||||
input_count(count_flop& button, uint32_t input, uint32_t mask)
|
||||
{
|
||||
if ((input & mask) == 0) {
|
||||
if (button.count < input_debounce)
|
||||
button.count += 1;
|
||||
else
|
||||
button.das += 1;
|
||||
} else {
|
||||
if (button.count == 0) {
|
||||
button.flop = 0;
|
||||
button.das = 0;
|
||||
button.repeat = 0;
|
||||
}
|
||||
else if (button.count > 0)
|
||||
button.count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
input_flopped(count_flop& button)
|
||||
{
|
||||
if (button.count == input_debounce && button.flop == 0) {
|
||||
button.flop = 1;
|
||||
return 1;
|
||||
} else if (button.flop == 1 && button.das == input_das && button.repeat == 0) {
|
||||
button.repeat = 1;
|
||||
button.das = 0;
|
||||
return 2;
|
||||
} else if (button.repeat == 1 && (button.das == input_arr)) {
|
||||
button.das = 0;
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct cursor {
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
|
||||
void left() { do { x = (x - 1) & 7; } while (!grid[y][x]); }
|
||||
void right() { do { x = (x + 1) & 7; } while (!grid[y][x]); }
|
||||
void up()
|
||||
{
|
||||
y -= 1;
|
||||
if (y < 0) y = 6;
|
||||
while (!grid[y][x]) { x--; };
|
||||
}
|
||||
void down()
|
||||
{
|
||||
y += 1;
|
||||
if (y > 6) y = 0;
|
||||
while (!grid[y][x]) { x--; };
|
||||
}
|
||||
};
|
||||
|
||||
struct state {
|
||||
uint8_t slot_ix;
|
||||
struct input input;
|
||||
struct cursor cursor;
|
||||
};
|
||||
|
||||
static struct state state = { 0 };
|
||||
|
||||
void digital_callback(uint8_t fsm_state, uint8_t data)
|
||||
{
|
||||
switch (fsm_state) {
|
||||
case intback::DATA1:
|
||||
input_count(state.input.right, data, DIGITAL__1__RIGHT);
|
||||
input_count(state.input.left, data, DIGITAL__1__LEFT);
|
||||
input_count(state.input.down, data, DIGITAL__1__DOWN);
|
||||
input_count(state.input.up, data, DIGITAL__1__UP);
|
||||
input_count(state.input.start, data, DIGITAL__1__START);
|
||||
input_count(state.input.a, data, DIGITAL__1__A);
|
||||
input_count(state.input.c, data, DIGITAL__1__C);
|
||||
input_count(state.input.b, data, DIGITAL__1__B);
|
||||
break;
|
||||
case intback::DATA2:
|
||||
input_count(state.input.r, data, DIGITAL__2__R);
|
||||
input_count(state.input.x, data, DIGITAL__2__X);
|
||||
input_count(state.input.y, data, DIGITAL__2__Y);
|
||||
input_count(state.input.z, data, DIGITAL__2__Z);
|
||||
input_count(state.input.l, data, DIGITAL__2__L);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void smpc_int(void) __attribute__ ((interrupt_handler));
|
||||
void smpc_int(void)
|
||||
{
|
||||
scu.reg.IST &= ~(IST__SMPC);
|
||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||
|
||||
intback::fsm(digital_callback, nullptr);
|
||||
}
|
||||
|
||||
constexpr int32_t plane_a = 2;
|
||||
constexpr inline int32_t plane_offset(int32_t n) { return n * 0x2000; }
|
||||
|
||||
constexpr int32_t page_size = 64 * 64 * 2; // N0PNB__1WORD (16-bit)
|
||||
constexpr int32_t plane_size = page_size * 1;
|
||||
|
||||
constexpr int32_t cell_size = (8 * 8) / 2; // N0CHCN__16_COLOR (4-bit)
|
||||
constexpr int32_t character_size = cell_size * (1 * 1); // N0CHSZ__1x1_CELL
|
||||
constexpr int32_t page_width = 64;
|
||||
|
||||
static int plane_ix = 0;
|
||||
|
||||
inline void
|
||||
set_char(int32_t x, int32_t y, uint8_t palette, uint8_t c)
|
||||
{
|
||||
const auto ix = (plane_offset(plane_a + plane_ix) / 2) + (y * page_width) + x;
|
||||
vdp2.vram.u16[ix] =
|
||||
PATTERN_NAME_TABLE_1WORD__PALETTE(palette)
|
||||
| PATTERN_NAME_TABLE_1WORD__CHARACTER((c - 0x20));
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
// 012345678901234
|
||||
uint8_t label[] = "scsp.reg.slot[ ]";
|
||||
string::hex(&label[14], 2, state.slot_ix);
|
||||
for (uint32_t i = 0; label[i] != 0; i++) {
|
||||
set_char(0 + i, 1, 0, label[i]);
|
||||
}
|
||||
|
||||
constexpr int32_t y_offset = 3;
|
||||
|
||||
for (uint32_t f_ix = u(scsp_name::FIRST); f_ix <= u(scsp_name::LAST); f_ix++) {
|
||||
label_value& lv = label_value_table[f_ix];
|
||||
for (uint32_t i = 0; lv.name[i] != 0; i++) {
|
||||
set_char(lv.label.x + i, lv.label.y + y_offset, 0, lv.name[i]);
|
||||
}
|
||||
|
||||
uint8_t buf[lv.len];
|
||||
scsp_name name = static_cast<scsp_name>(f_ix);
|
||||
uint32_t value = get_reg(scsp.reg.slot[state.slot_ix], name);
|
||||
string::hex(buf, lv.len, value);
|
||||
bool selected = !(!grid[state.cursor.y][state.cursor.x]) && name == *grid[state.cursor.y][state.cursor.x];
|
||||
uint32_t palette = selected ? 1 : 0;
|
||||
for (uint32_t i = 0; i < lv.len; i++) {
|
||||
set_char(lv.value.x + i, lv.value.y + y_offset, palette, buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace event {
|
||||
inline bool prev_slot() { return input_flopped(state.input.l) == 1; }
|
||||
inline bool next_slot() { return input_flopped(state.input.r) == 1; }
|
||||
inline bool cursor_left() { return input_flopped(state.input.left ) >= 1; }
|
||||
inline bool cursor_right() { return input_flopped(state.input.right) >= 1; }
|
||||
inline bool cursor_up() { return input_flopped(state.input.up ) >= 1; }
|
||||
inline bool cursor_down() { return input_flopped(state.input.down ) >= 1; }
|
||||
inline bool cursor_dec() { return input_flopped(state.input.x ) >= 1; }
|
||||
inline bool cursor_inc() { return input_flopped(state.input.y ) >= 1; }
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
if (event::prev_slot())
|
||||
state.slot_ix = (state.slot_ix - 1) & 31;
|
||||
if (event::next_slot())
|
||||
state.slot_ix = (state.slot_ix + 1) & 31;
|
||||
if (event::cursor_left()) state.cursor.left();
|
||||
if (event::cursor_right()) state.cursor.right();
|
||||
if (event::cursor_up()) state.cursor.up();
|
||||
if (event::cursor_down()) state.cursor.down();
|
||||
if (grid[state.cursor.y][state.cursor.x]) {
|
||||
if (event::cursor_inc()) incdec_reg(scsp.reg.slot[state.slot_ix], *grid[state.cursor.y][state.cursor.x], +1);
|
||||
if (event::cursor_dec()) incdec_reg(scsp.reg.slot[state.slot_ix], *grid[state.cursor.y][state.cursor.x], -1);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
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__SMPC | IMS__V_BLANK_IN);
|
||||
|
||||
// flip planes;
|
||||
vdp2.reg.MPABN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(plane_a + plane_ix);
|
||||
plane_ix = !plane_ix;
|
||||
|
||||
// wait at least 300us, as specified in the SMPC manual.
|
||||
// It appears reading FRC.H is mandatory and *must* occur before FRC.L on real
|
||||
// hardware.
|
||||
while ((sh2.reg.FTCSR & FTCSR__OVF) == 0 && sh2.reg.FRC.H == 0 && sh2.reg.FRC.L < 63);
|
||||
|
||||
if ((vdp2.reg.TVSTAT & TVSTAT__VBLANK) != 0) {
|
||||
// on real hardware, SF contains uninitialized garbage bits other than the
|
||||
// lsb.
|
||||
while ((smpc.reg.SF & 1) != 0);
|
||||
|
||||
smpc.reg.SF = 0;
|
||||
|
||||
smpc.reg.IREG[0].val = INTBACK__IREG0__STATUS_DISABLE;
|
||||
smpc.reg.IREG[1].val = ( INTBACK__IREG1__PERIPHERAL_DATA_ENABLE
|
||||
| INTBACK__IREG1__PORT2_15BYTE
|
||||
| INTBACK__IREG1__PORT1_15BYTE
|
||||
);
|
||||
smpc.reg.IREG[2].val = INTBACK__IREG2__MAGIC;
|
||||
|
||||
smpc.reg.COMREG = COMREG__INTBACK;
|
||||
}
|
||||
|
||||
update();
|
||||
render();
|
||||
}
|
||||
|
||||
void init_slots()
|
||||
{
|
||||
while ((smpc.reg.SF & 1) != 0);
|
||||
smpc.reg.SF = 1;
|
||||
smpc.reg.COMREG = COMREG__SNDON;
|
||||
while (smpc.reg.OREG[31].val != 0b00000110);
|
||||
|
||||
for (long i = 0; i < 807; i++) { asm volatile ("nop"); } // wait for (way) more than 30µs
|
||||
|
||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB | MIXER__MVOL(0);
|
||||
|
||||
const uint32_t * buf = reinterpret_cast<uint32_t*>(&_sine_start);
|
||||
const uint32_t size = reinterpret_cast<uint32_t>(&_sine_size);
|
||||
copy<uint32_t>(&scsp.ram.u32[0], buf, size);
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
scsp_slot& slot = scsp.reg.slot[i];
|
||||
// start address (bytes)
|
||||
slot.SA = SA__KYONB | SA__LPCTL__NORMAL | SA__SA(0); // kx kb sbctl[1:0] ssctl[1:0] lpctl[1:0] 8b sa[19:0]
|
||||
slot.LSA = 0; // loop start address (samples)
|
||||
slot.LEA = 100; // loop end address (samples)
|
||||
slot.EG = EG__EGHOLD; // d2r d1r ho ar krs dl rr
|
||||
slot.FM = 0; // stwinh sdir tl mdl mdxsl mdysl
|
||||
slot.PITCH = PITCH__OCT(0) | PITCH__FNS(0); // oct fns
|
||||
slot.LFO = 0; // lfof plfows
|
||||
slot.MIXER = MIXER__DISDL(0b101); // disdl dipan efsdl efpan
|
||||
}
|
||||
|
||||
scsp.reg.ctrl.MIXER = MIXER__MEM4MB | MIXER__MVOL(0xf);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
init_slots();
|
||||
|
||||
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);
|
||||
|
||||
/* set the color mode to 5bits per channel, 1024 colors */
|
||||
vdp2.reg.RAMCTL = RAMCTL__CRMD__RGB_5BIT_1024;
|
||||
|
||||
/* enable display of NBG0 */
|
||||
vdp2.reg.BGON = BGON__N0ON;
|
||||
|
||||
/* set character format for NBG0 to palettized 16 color
|
||||
set enable "cell format" for NBG0
|
||||
set character size for NBG0 to 1x1 cell */
|
||||
vdp2.reg.CHCTLA = CHCTLA__N0CHCN__16_COLOR
|
||||
| CHCTLA__N0BMEN__CELL_FORMAT
|
||||
| CHCTLA__N0CHSZ__1x1_CELL;
|
||||
/* "Note: In color RAM modes 0 and 2, 2048-color becomes 1024-color" */
|
||||
|
||||
/* use 1-word (16-bit) pattern names */
|
||||
vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD;
|
||||
|
||||
/* plane size */
|
||||
vdp2.reg.PLSZ = PLSZ__N0PLSZ__1x1;
|
||||
|
||||
/* map plane offset
|
||||
1-word: value of bit 6-0 * 0x2000
|
||||
2-word: value of bit 5-0 * 0x4000
|
||||
*/
|
||||
vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 8~6
|
||||
vdp2.reg.MPABN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(plane_a); // bits 5~0
|
||||
vdp2.reg.MPCDN0 = MPABN0__N0MPD(0) | MPABN0__N0MPC(0); // bits 5~0
|
||||
|
||||
// zeroize character/cell data from 0 up to plane_a_offset
|
||||
fill<uint32_t>(&vdp2.vram.u32[(0 / 4)], 0, plane_offset(plane_a));
|
||||
|
||||
// zeroize plane_a; `0` is the ascii 0x20 ("space") which doubles as
|
||||
// "transparency" character.
|
||||
fill<uint32_t>(&vdp2.vram.u32[(plane_offset(plane_a) / 4)], 0, plane_size * 2);
|
||||
|
||||
palette_data();
|
||||
cell_data();
|
||||
|
||||
// free-running timer
|
||||
sh2.reg.TCR = TCR__CKS__INTERNAL_DIV128;
|
||||
sh2.reg.FTCSR = 0;
|
||||
|
||||
// initialize smpc
|
||||
smpc.reg.DDR1 = 0; // INPUT
|
||||
smpc.reg.DDR2 = 0; // INPUT
|
||||
smpc.reg.IOSEL = 0; // SMPC control
|
||||
smpc.reg.EXLE = 0; //
|
||||
|
||||
sh2_vec[SCU_VEC__SMPC] = (u32)(&smpc_int);
|
||||
sh2_vec[SCU_VEC__V_BLANK_IN] = (u32)(&v_blank_in_int);
|
||||
|
||||
scu.reg.IST = 0;
|
||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||
}
|
Binary file not shown.
@ -4,7 +4,7 @@
|
||||
|
||||
#include "../common/copy.hpp"
|
||||
|
||||
extern void * _sine_start __asm("_binary_scsp_sine_44100_s16be_1ch_pcm_start");
|
||||
extern void * _sine_start __asm("_binary_scsp_sine_44100_s16be_1ch_1sec_pcm_start");
|
||||
|
||||
void main()
|
||||
{
|
||||
@ -26,8 +26,7 @@ void main()
|
||||
slot.LSA = 0; // loop start address (samples)
|
||||
slot.LEA = 44100; // loop end address (samples)
|
||||
slot.EG = EG__EGHOLD; // d2r d1r ho ar krs dl rr
|
||||
slot.VOLUME = 0; // stwinh sdir tl
|
||||
slot.FM = 0; // mdl mdxsl mdysl
|
||||
slot.FM = 0; // stwinh sdir tl mdl mdxsl mdysl
|
||||
slot.PITCH = PITCH__OCT(0) | PITCH__FNS(0); // oct fns
|
||||
slot.LFO = 0; // lfof plfows
|
||||
slot.MIXER = MIXER__DISDL(0b101); // disdl dipan efsdl efpan
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "../common/draw_font.hpp"
|
||||
#include "../common/palette.hpp"
|
||||
#include "../common/vdp2_func.hpp"
|
||||
#include "../common/string.hpp"
|
||||
|
||||
extern void * _m68k_start __asm("_binary_m68k_interrupt_bin_start");
|
||||
extern void * _m68k_size __asm("_binary_m68k_interrupt_bin_size");
|
||||
@ -24,27 +25,6 @@ struct draw_state {
|
||||
|
||||
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,
|
||||
@ -171,7 +151,7 @@ inline void draw_label(const uint8_t(&label)[size], int32_t advance, int32_t & r
|
||||
advance = (advance * 8) << 6;
|
||||
advance += draw_string(label, (sizeof (label)) - 1, advance, row);
|
||||
uint8_t v[n];
|
||||
print_hex(v, (sizeof (v)), value);
|
||||
string::hex(v, (sizeof (v)), value);
|
||||
draw_string(v, (sizeof (v)), advance, row);
|
||||
|
||||
row++;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "../common/draw_font.hpp"
|
||||
#include "../common/palette.hpp"
|
||||
#include "../common/vdp2_func.hpp"
|
||||
#include "../common/string.hpp"
|
||||
|
||||
/* begin font */
|
||||
|
||||
@ -149,27 +150,6 @@ static xy foo[2] = {
|
||||
{200, 100}
|
||||
};
|
||||
|
||||
uint32_t print_hex(char16_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;
|
||||
}
|
||||
|
||||
static struct draw_font::state font_state;
|
||||
|
||||
static uint32_t global_cmd_ix = 0;
|
||||
@ -240,7 +220,7 @@ void smpc_int(void) {
|
||||
static int32_t y = 50 << 6;
|
||||
|
||||
if (kbd_bits & 0b1000) {
|
||||
print_hex(str_num, 2, keysym);
|
||||
string::hex(str_num, 2, keysym);
|
||||
|
||||
enum keysym k = scancode_to_keysym(keysym);
|
||||
int32_t c = keysym_to_char(k, false);
|
||||
@ -268,7 +248,7 @@ void smpc_int(void) {
|
||||
draw_font::horizontal_string(font_state,
|
||||
cmd_ix, // modified
|
||||
&str_num[0],
|
||||
2,
|
||||
2,
|
||||
qx,
|
||||
qy);
|
||||
}
|
||||
|
@ -42,8 +42,10 @@ uint32_t xorshift32(struct xorshift32_state *state)
|
||||
static xorshift32_state random_state = { 0x12345678 };
|
||||
static uint32_t frame_count = 0;
|
||||
|
||||
void keyboard_callback(const enum keysym k, uint8_t kbd_bits)
|
||||
void keyboard_callback(uint8_t kbd_bits, uint8_t scancode)
|
||||
{
|
||||
enum keysym k = scancode_to_keysym(scancode);
|
||||
|
||||
if (!KEYBOARD__MAKE(kbd_bits))
|
||||
return;
|
||||
|
||||
@ -71,7 +73,7 @@ void smpc_int(void)
|
||||
scu.reg.IST &= ~(IST__SMPC);
|
||||
scu.reg.IMS = ~(IMS__SMPC | IMS__V_BLANK_IN);
|
||||
|
||||
intback::keyboard_fsm(keyboard_callback);
|
||||
intback::fsm(nullptr, keyboard_callback);
|
||||
}
|
||||
|
||||
// rendering
|
||||
@ -140,9 +142,9 @@ void v_blank_in_int()
|
||||
|
||||
smpc.reg.IREG[0].val = INTBACK__IREG0__STATUS_DISABLE;
|
||||
smpc.reg.IREG[1].val = ( INTBACK__IREG1__PERIPHERAL_DATA_ENABLE
|
||||
| INTBACK__IREG1__PORT2_15BYTE
|
||||
| INTBACK__IREG1__PORT1_15BYTE
|
||||
);
|
||||
| INTBACK__IREG1__PORT2_15BYTE
|
||||
| INTBACK__IREG1__PORT1_15BYTE
|
||||
);
|
||||
smpc.reg.IREG[2].val = INTBACK__IREG2__MAGIC;
|
||||
|
||||
smpc.reg.COMREG = COMREG__INTBACK;
|
||||
|
Loading…
x
Reference in New Issue
Block a user