Compare commits

..

12 Commits

38 changed files with 52658 additions and 16 deletions

3
.gitignore vendored
View File

@ -11,9 +11,12 @@
*.pcm
*.su
*.ss
*.dsp
*.exe
res/mai.data
tools/ttf-convert
tools/ttf-bitmap
tools/ttf_bitmap2
common/keyboard.cpp
common/keyboard.hpp
wordle/word_list.hpp

View File

@ -1,5 +1,5 @@
CFLAGS = -Isaturn
OPT ?= -Og
CFLAGS = -Isaturn -I. -D__saturn__
OPT ?= -O2
LIB = ./saturn
ALL =
@ -28,6 +28,9 @@ include $(LIB)/common.mk
%.data.o: %.data
$(BUILD_BINARY_O)
%.data.h: %.data
$(BUILD_BINARY_H)
%.pattern.o: %.pattern
$(BUILD_BINARY_O)
@ -37,6 +40,15 @@ include $(LIB)/common.mk
%.bin.o: %.bin
$(BUILD_BINARY_O)
%.bin.h: %.bin
$(BUILD_BINARY_H)
%.dsp.o: %.dsp
$(BUILD_BINARY_O)
%.dsp.h: %.dsp
$(BUILD_BINARY_H)
%.pcm.o: %.pcm
$(BUILD_BINARY_O)
@ -52,11 +64,19 @@ vdp2/nbg0.elf: vdp2/nbg0.o res/butterfly.data.o res/butterfly.data.pal.o
vdp2/nbg0_16color.elf: vdp2/nbg0_16color.o res/kirby.data.o res/kirby.data.pal.o
vdp2/nbg0_font.elf: vdp2/nbg0_font.o saturn/start.o font/hp_100lx_4bit.data.o
vdp2/rbg0_font.elf: vdp2/rbg0_font.o saturn/start.o font/hp_100lx_4bit.data.o
vdp2/color_calculation_ratio.elf: vdp2/color_calculation_ratio.o res/mai00.data.o res/mai.data.pal.o res/haohmaru.data.o res/haohmaru.data.pal.o res/forest.data.pal.o res/forest.pattern.o res/forest.tile.o
vdp2/line_color_screen.elf: vdp2/line_color_screen.o $(LIBGCC)
vdp1/polygon.elf: vdp1/polygon.o
vdp1/cube.elf: vdp1/cube.o $(LIBGCC)
vdp1/cube2.elf: vdp1/cube2.o
vdp1/bear.elf: CFLAGS += -DUSE_SH2_DVSR
vdp1/bear.elf: vdp1/bear.o $(LIBGCC)
vdp1/normal_sprite.elf: vdp1/normal_sprite.o res/mai00.data.o res/mai.data.pal.o
vdp1/normal_sprite_color_bank.elf: vdp1/normal_sprite_color_bank.o res/mai00.data.o res/mai.data.pal.o
@ -153,6 +173,15 @@ editor/main_saturn.elf: editor/main_saturn.o res/nec.bitmap.bin.o res/nec_bold.b
cdc/cdc.elf: cdc/cdc.o saturn/start.o memcpy.o cdc/serial.o
scu-dsp/add.elf: scu-dsp/add.o saturn/start.o cdc/serial.o scu-dsp/input.bin.o
scu-dsp/div10.elf: scu-dsp/div10.o saturn/start.o cdc/serial.o scu-dsp/div10.dsp.o
scu-dsp/div10_vdp2.elf: scu-dsp/div10_vdp2.o saturn/start.o cdc/serial.o scu-dsp/div10_vdp2.dsp.o font/hp_100lx_4bit_flip.data.o
%.dsp: %.asm
~/scu-dsp-asm/scu-dsp-asm $< $@
# clean
clean: clean-sh
clean-sh:

View File

@ -4,14 +4,14 @@
void serial_char(const char c)
{
while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
//while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
sh2.reg.TDR = c;
}
void serial_string(const char * s)
{
while (*s) {
while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
//while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
sh2.reg.TDR = *s++;
}
}
@ -19,7 +19,7 @@ void serial_string(const char * s)
void serial_bytes(const char * s, uint32_t length)
{
while (length > 0) {
while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
//while ((sh2.reg.SSR & SSR__TDRE) == 0); // wait for transmit data empty
sh2.reg.TDR = *s++;
length -= 1;
}

BIN
font/Bm437_HP_100LX_8x8.otb Normal file

Binary file not shown.

BIN
font/hp_100lx_4bit.data Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_font_hp_100lx_4bit_data_start __asm("_binary_font_hp_100lx_4bit_data_start");
extern uint32_t _binary_font_hp_100lx_4bit_data_end __asm("_binary_font_hp_100lx_4bit_data_end");
extern uint32_t _binary_font_hp_100lx_4bit_data_size __asm("_binary_font_hp_100lx_4bit_data_size");

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_font_hp_100lx_4bit_flip_data_start __asm("_binary_font_hp_100lx_4bit_flip_data_start");
extern uint32_t _binary_font_hp_100lx_4bit_flip_data_end __asm("_binary_font_hp_100lx_4bit_flip_data_end");
extern uint32_t _binary_font_hp_100lx_4bit_flip_data_size __asm("_binary_font_hp_100lx_4bit_flip_data_size");

105
math/mat2x2.hpp Normal file
View File

@ -0,0 +1,105 @@
#pragma once
#include <utility>
#include "vec2.hpp"
template <int R, int C, typename T>
struct mat;
//
// mat4x4
//
template <typename T>
struct mat<2, 2, T>
{
typedef vec<2, T> row_type;
typedef vec<2, T> col_type;
private:
row_type value[2];
public:
inline constexpr mat();
inline constexpr mat
(
T const& a00, T const& a01,
T const& a10, T const& a11
);
inline static constexpr int length() { return 4; }
inline constexpr typename mat<2, 2, T>::row_type const &
operator[](int i) const;
void operator=(const mat<2, 2, T>&) = delete;
};
template<typename T>
inline constexpr mat<2, 2, T>::mat()
: value{std::move(row_type(1, 0)),
std::move(row_type(0, 1))}
{ }
template<typename T>
inline constexpr mat<2, 2, T>::mat
(
T const& a00, T const& a01,
T const& a10, T const& a11
)
: value{std::move(row_type(a00, a01)),
std::move(row_type(a10, a11))}
{ }
template <typename T>
inline constexpr typename mat<2, 2, T>::row_type const &
mat<2, 2, T>::operator[](int i) const
{
switch (i)
{
default: [[fallthrough]];
case 0:
return value[0];
case 1:
return value[1];
}
}
template<typename T>
inline constexpr mat<2, 2, T> operator*(mat<2, 2, T> const& m1, mat<2, 2, T> const& m2)
{
#define c(i, j) ( \
m1[i][0] * m2[0][j] \
+ m1[i][1] * m2[1][j])
return mat<2, 2, T>(c(0,0), c(0,1),
c(1,0), c(1,1));
#undef c
}
template<typename T>
inline constexpr typename mat<2, 2, T>::row_type operator*
(
mat<2, 2, T> const& m,
typename mat<2, 2, T>::col_type const& v
)
{
#define c(i) ( \
m[i][0] * v[0] \
+ m[i][1] * v[1])
return typename mat<2, 2, T>::row_type(c(0), c(1));
#undef c
}
template<typename T>
inline constexpr mat<2, 2, T> transpose(mat<2, 2, T> const& m)
{
return mat<2, 2, T>(
m[0][0], m[1][0],
m[0][1], m[1][1]
);
}

View File

@ -74,6 +74,17 @@ mat<3, 3, T>::operator[](int i) const
}
}
template<typename T>
inline constexpr mat<3, 3, T> operator+(mat<3, 3, T> const& m1, mat<3, 3, T> const& m2)
{
#define c(i, j) ( m1[i][j] + m2[i][j] )
return mat<3, 3, T>(c(0,0), c(0,1), c(0,2),
c(1,0), c(1,1), c(1,2),
c(2,0), c(2,1), c(2,2));
#undef c
}
template<typename T>
inline constexpr mat<3, 3, T> operator*(mat<3, 3, T> const& m1, mat<3, 3, T> const& m2)
{
@ -88,6 +99,17 @@ inline constexpr mat<3, 3, T> operator*(mat<3, 3, T> const& m1, mat<3, 3, T> con
#undef c
}
template<typename T>
inline constexpr mat<3, 3, T> operator*(mat<3, 3, T> const& m1, float s)
{
#define c(i, j) ( m1[i][j] * s )
return mat<3, 3, T>(c(0,0), c(0,1), c(0,2),
c(1,0), c(1,1), c(1,2),
c(2,0), c(2,1), c(2,2));
#undef c
}
template<typename T>
inline constexpr typename mat<3, 3, T>::row_type operator*
(

View File

@ -35,7 +35,7 @@ public:
inline constexpr typename mat<4, 4, T>::row_type const &
operator[](int i) const;
void operator=(const mat<4, 4, T>&) = delete;
//void operator=(const mat<4, 4, T>&) = delete;
};
@ -80,6 +80,18 @@ mat<4, 4, T>::operator[](int i) const
}
}
template<typename T>
inline constexpr mat<4, 4, T> operator+(mat<4, 4, T> const& m1, mat<4, 4, T> const& m2)
{
#define c(i, j) ( m1[i][j] + m2[i][j] )
return mat<4, 4, T>(c(0,0), c(0,1), c(0,2), c(0,3),
c(1,0), c(1,1), c(1,2), c(1,3),
c(2,0), c(2,1), c(2,2), c(2,3),
c(3,0), c(3,1), c(3,2), c(3,3));
#undef c
}
template<typename T>
inline constexpr mat<4, 4, T> operator*(mat<4, 4, T> const& m1, mat<4, 4, T> const& m2)
{
@ -96,6 +108,18 @@ inline constexpr mat<4, 4, T> operator*(mat<4, 4, T> const& m1, mat<4, 4, T> con
#undef c
}
template<typename T>
inline constexpr mat<4, 4, T> operator*(mat<4, 4, T> const& m1, float s)
{
#define c(i, j) ( m1[i][j] * s )
return mat<4, 4, T>(c(0,0), c(0,1), c(0,2), c(0,3),
c(1,0), c(1,1), c(1,2), c(1,3),
c(2,0), c(2,1), c(2,2), c(2,3),
c(3,0), c(3,1), c(3,2), c(3,3));
#undef c
}
template<typename T>
inline constexpr typename mat<4, 4, T>::row_type operator*
(
@ -113,6 +137,23 @@ inline constexpr typename mat<4, 4, T>::row_type operator*
#undef c
}
template<typename T>
inline constexpr vec<3, T> operator*
(
mat<4, 4, T> const& m,
vec<3, T> const& v
)
{
#define c(i) ( \
m[i][0] * v[0] \
+ m[i][1] * v[1] \
+ m[i][2] * v[2] \
+ m[i][3] )
return vec<3, T>(c(0), c(1), c(2));
#undef c
}
template<typename T>
inline constexpr mat<4, 4, T> transpose(mat<4, 4, T> const& m)
{

158
math/vec2.hpp Normal file
View File

@ -0,0 +1,158 @@
#pragma once
#include "math.hpp"
#include "vec.hpp"
//
// vec3
//
template <typename T>
struct vec<2, T>
{
union {
struct { T x, y; };
struct { T u, v; };
};
inline constexpr vec();
inline constexpr vec(T scalar);
inline constexpr vec(T _x, T _y);
constexpr inline vec<2, T> operator-() const;
inline constexpr T const& operator[](int i) const;
inline constexpr vec<2, T>& operator=(vec<2, T> const& v);
inline constexpr vec<2, T>& operator+=(vec<2, T> const& v);
inline constexpr vec<2, T>& operator-=(vec<2, T> const& v);
};
template <typename T>
inline constexpr vec<2, T>::vec()
: x(0), y(0)
{}
template <typename T>
inline constexpr vec<2, T>::vec(T scalar)
: x(scalar), y(scalar)
{}
template <typename T>
inline constexpr vec<2, T>::vec(T _x, T _y)
: x(_x), y(_y)
{}
template <typename T>
constexpr inline vec<2, T> vec<2, T>::operator-() const
{
return vec<2, T>(-x, -y);
}
template <typename T>
inline constexpr T const& vec<2, T>::operator[](int i) const
{
switch(i)
{
default: [[fallthrough]];
case 0: return x;
case 1: return y;
}
}
template <typename T>
inline constexpr vec<2, T>& vec<2, T>::operator=(vec<2, T> const& v)
{
this->x = static_cast<T>(v.x);
this->y = static_cast<T>(v.y);
return *this;
}
template <typename T>
inline constexpr vec<2, T>& vec<2, T>::operator+=(vec<2, T> const& v)
{
*this = *this + vec<2, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<2, T>& vec<2, T>::operator-=(vec<2, T> const& v)
{
*this = *this - vec<2, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<2, T> operator+(vec<2, T> const& v1, vec<2, T> const& v2)
{
return vec<2, T>(v1.x + v2.x,
v1.y + v2.y);
}
template <typename T>
inline constexpr vec<2, T> operator-(vec<2, T> const& v1, vec<2, T> const& v2)
{
return vec<2, T>(v1.x - v2.x,
v1.y - v2.y);
}
template <typename T>
inline constexpr vec<2, T> operator*(vec<2, T> const& v1, vec<2, T> const& v2)
{
return vec<2, T>(v1.x * v2.x,
v1.y * v2.y);
}
template <typename T>
inline constexpr vec<2, T> operator*(vec<2, T> const& v1, T const& scalar)
{
return v1 * vec<2, T>(scalar);
}
template <typename T>
inline constexpr vec<2, T> operator*(T const& scalar, vec<2, T> const& v1)
{
return vec<2, T>(scalar) * v1;
}
template <typename T>
inline constexpr vec<2, T> operator/(vec<2, T> const& v1, vec<2, T> const& v2)
{
return vec<2, T>(v1.x / v2.x,
v1.y / v2.y);
}
template <typename T>
inline constexpr vec<2, T> operator/(vec<2, T> const& v1, T const& scalar)
{
return v1 / vec<2, T>(scalar);
}
template <typename T>
inline constexpr T dot(vec<2, T> const& v1, vec<2, T> const& v2)
{
vec<2, T> tmp(v1 * v2);
return tmp.x + tmp.y;
}
template <typename T>
inline constexpr T cross(vec<2, T> const& v1, vec<2, T> const& v2)
{
return v1.x * v2.y - v2.x * v1.y;
}
template <typename T>
inline constexpr vec<2, T> functor1(T (&func) (T const& x), vec<2, T> const& v)
{
return vec<2, T>(func(v.x), func(v.y));
}
template <typename T, typename U>
inline constexpr vec<2, U> functor1(U (&func) (T const& x), vec<2, T> const& v)
{
return vec<2, U>(func(v.x), func(v.y));
}
template <typename T>
inline constexpr T magnitude(vec<2, T> const& v)
{
return sqrt(dot(v, v));
}

View File

@ -10,7 +10,10 @@
template <typename T>
struct vec<3, T>
{
T x, y, z;
union {
struct { T x, y, z; };
struct { T r, g, b; };
};
inline constexpr vec();
inline constexpr vec(T scalar);
@ -109,6 +112,12 @@ inline constexpr vec<3, T> operator*(vec<3, T> const& v1, T const& scalar)
return v1 * vec<3, T>(scalar);
}
template <typename T>
inline constexpr vec<3, T> operator*(T const& scalar, vec<3, T> const& v1)
{
return vec<3, T>(scalar) * v1;
}
template <typename T>
inline constexpr vec<3, T> operator/(vec<3, T> const& v1, vec<3, T> const& v2)
{
@ -130,6 +139,14 @@ inline constexpr T dot(vec<3, T> const& v1, vec<3, T> const& v2)
return tmp.x + tmp.y + tmp.z;
}
template <typename T>
inline constexpr vec<3, T> cross(vec<3, T> const& v1, vec<3, T> const& v2)
{
return vec<3, T>(v1.y * v2.z - v2.y * v1.z,
v1.z * v2.x - v2.z * v1.x,
v1.x * v2.y - v2.x * v1.y);
}
template <typename T>
inline constexpr vec<3, T> functor1(T (&func) (T const& x), vec<3, T> const& v)
{
@ -143,15 +160,7 @@ inline constexpr vec<3, U> functor1(U (&func) (T const& x), vec<3, T> const& v)
}
template <typename T>
inline constexpr T length(vec<3, T> const& v)
inline constexpr T magnitude(vec<3, T> const& v)
{
return sqrt(dot(v, v));
}
template<typename T>
inline constexpr vec<3, T> cross(vec<3, T> const& x, vec<3, T> const& y)
{
return vec<3, T>(x.y * y.z - y.y * x.z,
x.z * y.x - y.z * x.x,
x.x * y.y - y.x * x.y);
}

BIN
model/bear/bear.data Normal file

Binary file not shown.

15
model/bear/bear.data.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_model_bear_bear_data_start __asm("_binary_model_bear_bear_data_start");
extern uint32_t _binary_model_bear_bear_data_end __asm("_binary_model_bear_bear_data_end");
extern uint32_t _binary_model_bear_bear_data_size __asm("_binary_model_bear_bear_data_size");
#ifdef __cplusplus
}
#endif

22
model/bear/bear.mtl Normal file
View File

@ -0,0 +1,22 @@
# Blender 4.3.2 MTL File: 'bear.blend'
# www.blender.org
newmtl matBear
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1
newmtl matOutline
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 0.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1

3407
model/bear/bear0000.obj Normal file

File diff suppressed because it is too large Load Diff

3407
model/bear/bear0005.obj Normal file

File diff suppressed because it is too large Load Diff

3407
model/bear/bear0010.obj Normal file

File diff suppressed because it is too large Load Diff

3407
model/bear/bear0015.obj Normal file

File diff suppressed because it is too large Load Diff

3407
model/bear/bear0020.obj Normal file

File diff suppressed because it is too large Load Diff

13
model/bear/material.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
#include "model/material.h"
enum material {
bear_matBear,
bear_matOutline,
};
const struct material_descriptor bear_material[] = {
};

33616
model/bear/model.h Normal file

File diff suppressed because it is too large Load Diff

25
model/material.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
struct pixel_descriptor {
uint8_t * start;
int32_t size;
int32_t vram_offset; // offset into vram texture address space
int16_t width;
int16_t height;
};
struct palette_descriptor {
uint8_t * start;
int32_t size;
int32_t vram_offset; // offset into vram palette address space
int32_t palette_size;
};
struct material_descriptor {
struct pixel_descriptor pixel;
struct palette_descriptor palette;
};

59
model/model.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <stdint.h>
#include "math/vec3.hpp"
#include "math/vec2.hpp"
#ifdef __dreamcast__
using vertex_position = vec<3, float>;
using vertex_normal = vec<3, float>;
using vertex_texture = vec<2, float>;
#endif
#ifdef __saturn__
#include "math/fp.hpp"
using vertex_position = vec<3, fp16_16>;
using vertex_normal = vec<3, fp16_16>;
using vertex_texture = vec<2, fp16_16>;
#endif
struct index_ptn {
uint16_t position;
uint16_t texture;
uint16_t normal;
};
union triangle {
struct {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
};
struct index_ptn v[3];
};
union quadrilateral {
struct {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
struct index_ptn d;
};
struct index_ptn v[4];
};
struct object {
const union triangle * triangle;
const union quadrilateral * quadrilateral;
const int triangle_count;
const int quadrilateral_count;
const int material;
};
struct model {
const vertex_position * position;
const vertex_texture * texture;
const vertex_normal * normal;
const struct object ** object;
const int object_count;
};

76
scu-dsp/div10.asm Normal file
View File

@ -0,0 +1,76 @@
mov 0,ct0 ; num
mov 0,ct1 ; vdp2 address
mov 0,ct3 ; output
mvi 12345,mc0 ; m0[0] (12345)
;; output: m3
base10_loop:
mov 0,ct0
mvi div10_unsigned,pc
;; [X ] [Y ] [D1 ]
mov mc0,y mov 1,lop ; mvi imm,pc delay slot (executed twice)
;; after function return:
mov all,mc0 ; m0[1] (1234)
mov all,pl ; ??? why can't this happen in the next instruction?
;; mod10: multiply by 10:
sl mov alu,a
sl mov alu,a
sl mov alu,a
add mov alu,a
add mov alu,a mov 0,ct0 ; restore ct0 after 'mov all,mc1'
;; a: 12340
mov mc0,a mov all,pl
;; a: 12345 m0[0]
;; p: 12340
;; mod10: subtract (a - p)
sub mov alu,a
;; a: 5
;; store digit in m3
mov mc0,p clr a mov all,mc3 ; m0[1]
;; p: 1234
;; a: 0
add mov alu,a mov 0,ct0
;; a: 1234
jmp nz,base10_loop
mov all,mc0 ; jmp delay slot
endi
nop
;; argument: ry
;; return: a ← ry / 10
;; maximum ry is somewhere between 2 ^ 21 and 2 ^ 22
div10_unsigned:
;; 1 / 10 * (2 ^ 24) ~= 1677722 = 0x19999a
mvi 1677722,rx
mov mul,p clr a
ad2 mov alu,a
;; ALH: [nmlkjihgfedcba9876543210________]
;; ALL: [76543210________________________]
clr a mov alh,pl ; alh is (a >> 16)
add mov alu,a
;; ALL: [nmlkjihgfedcba9876543210________]
;; rotate left 24 requires fewer cycles than shift right 8
rl8 mov alu,a
rl8 mov alu,a
rl8 mov alu,a
;; ALL: [________nmlkjihgfedcba9876543210]
;; mask 24 bit result
mvi 0xffffff,pl
;; return to caller ; reset ct0
btm
and mov alu,a mov 0,ct0

35
scu-dsp/div10.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "cdc/serial.h"
#include "scu.h"
#include "vdp2.h"
#include "scu-dsp/div10.dsp.h"
void main()
{
scu.reg.PPAF = 0; // stop execution
scu.reg.PPAF = (1 << 15) | 0; // reset PC
uint32_t * program = (uint32_t *)&_binary_scu_dsp_div10_dsp_start;
int program_length = ((int)&_binary_scu_dsp_div10_dsp_size) / 4;
for (int i = 0; i < program_length; i++) {
uint32_t p = program[i];
scu.reg.PPD = p;
serial_integer(p, 8, '\n');
}
scu.reg.PPAF = (1 << 16); // execute
int end_flag = 0;
while (end_flag == 0) {
end_flag = (scu.reg.PPAF >> 18) & 1;
}
scu.reg.PPAF = 0;
scu.reg.PDA = 64 * 3; // m3[0]
serial_string("answer:\n");
for (int i = 0; i < 8; i++) {
serial_integer(scu.reg.PDD, 8, '\n');
}
}

5
scu-dsp/div10.dsp.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_scu_dsp_div10_dsp_start __asm("_binary_scu_dsp_div10_dsp_start");
extern uint32_t _binary_scu_dsp_div10_dsp_end __asm("_binary_scu_dsp_div10_dsp_end");
extern uint32_t _binary_scu_dsp_div10_dsp_size __asm("_binary_scu_dsp_div10_dsp_size");

104
scu-dsp/div10_vdp2.asm Normal file
View File

@ -0,0 +1,104 @@
mov 0,ct0 ; num
mov 0,ct1 ; vdp2 address
mov 0,ct3 ; output
mvi 12345,mc0 ; m0[0] (12345)
;; clear m3
mov 7,lop
lps
mov 0,mc3
mov 0,ct3
;; output: m3
base10_loop:
mov 0,ct0
mvi div10_unsigned,pc
;; [X ] [Y ] [D1 ]
mov mc0,y mov 1,lop ; mvi imm,pc delay slot (executed twice)
;; after function return:
mov all,mc0 ; m0[1] (1234)
mov all,pl ; ??? why can't this happen in the next instruction?
;; mod10: multiply by 10:
sl mov alu,a
sl mov alu,a
sl mov alu,a
add mov alu,a
add mov alu,a mov 0,ct0 ; restore ct0 after 'mov all,mc1'
;; a: 12340
mov mc0,a mov all,pl
;; a: 12345 m0[0]
;; p: 12340
;; mod10: subtract (a - p)
sub mov alu,a
;; a: 5
;; convert to vdp2 character
mvi 16,pl
add mov alu,a
;; store digit in m3
mov mc0,p clr a mov all,mc3 ; m0[1]
;; p: 1234
;; a: 0
add mov alu,a mov 0,ct0
;; a: 1234
jmp nz,base10_loop
mov all,mc0 ; jmp delay slot
;;
;; transfer to vdp2
;;
;; vdp2 address calculation
mvi ((8 * 0x4000 + (64 - 8) * 4 + 0x05e00000) >> 2),wa0
mov 0,ct3
;; clr a mov 0,ct3
;; add mov alu,a
;; mov all,wa0
;; end vdp2 address calculation
dma1 mc3,d0,8
dma_wait:
jmp t0,dma_wait
nop
endi
nop
;; argument: ry
;; return: a ← ry / 10
;; maximum ry is somewhere between 2 ^ 21 and 2 ^ 22
div10_unsigned:
;; 1 / 10 * (2 ^ 24) ~= 1677722 = 0x19999a
mvi 1677722,rx
mov mul,p clr a
ad2 mov alu,a
;; ALH: [nmlkjihgfedcba9876543210________]
;; ALL: [76543210________________________]
clr a mov alh,pl ; alh is (a >> 16)
add mov alu,a
;; ALL: [nmlkjihgfedcba9876543210________]
;; rotate left 24 requires fewer cycles than shift right 8
rl8 mov alu,a
rl8 mov alu,a
rl8 mov alu,a
;; ALL: [________nmlkjihgfedcba9876543210]
;; mask 24 bit result
mvi 0xffffff,pl
;; return to caller ; reset ct0
btm
and mov alu,a mov 0,ct0

171
scu-dsp/div10_vdp2.cpp Normal file
View File

@ -0,0 +1,171 @@
#include "cdc/serial.h"
#include "scu.h"
#include "vdp2.h"
#include "../common/vdp2_func.hpp"
#include "scu-dsp/div10_vdp2.dsp.h"
#include "font/hp_100lx_4bit_flip.data.h"
void cell_data()
{
const uint32_t * start = reinterpret_cast<uint32_t *>(&_binary_font_hp_100lx_4bit_flip_data_start);
const int size = reinterpret_cast<uint32_t>(&_binary_font_hp_100lx_4bit_flip_data_size);
// the start of VRAM-A0
for (int i = 0; i < (size / 4); i++) {
vdp2.vram.u32[i] = start[i];
}
}
void palette_data()
{
vdp2.cram.u16[0] = 0x0000;
vdp2.cram.u16[1] = 0xffff;
}
void vdp2_init()
{
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
| RAMCTL__VRAMD
| RAMCTL__VRBMD
| RAMCTL__RDBSA0__CHARACTER_PATTERN_TABLE // VRAM-A0 0x000000
| RAMCTL__RDBSA1__PATTERN_NAME_TABLE; // VRAM-A1 0x020000
vdp2.reg.VRSIZE = 0;
/* enable display of NBG0 */
vdp2.reg.BGON = BGON__R0ON | BGON__R0TPON;
/* 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.CHCTLB = CHCTLB__R0CHCN__16_COLOR
| CHCTLB__R0BMEN__CELL_FORMAT
| CHCTLB__R0CHSZ__1x1_CELL;
/* plane size */
vdp2.reg.PLSZ = PLSZ__RAPLSZ__1x1
| PLSZ__RBPLSZ__1x1;
/* map plane offset
1-word: value of bit 6-0 * 0x2000
2-word: value of bit 5-0 * 0x4000
*/
// plane_a_offset is at the start of VRAM-A1
constexpr int plane_a = 8;
constexpr int plane_a_offset = plane_a * 0x4000;
constexpr int page_size = 64 * 64 * 2; // N0PNB__1WORD (16-bit)
constexpr int plane_size = page_size * 1;
/* cycle pattern table not used for RBG0 ? */
vdp2.reg.CYCA0 = 0x0F44F99F;
vdp2.reg.CYCA1 = 0x0F44F99F;
vdp2.reg.CYCB0 = 0x0F44F99F;
vdp2.reg.CYCB1 = 0x0F44F99F;
vdp2.reg.MPOFR = MPOFR__RAMP(0); // bits 8~6
vdp2.reg.MPABRA = MPABRA__RAMPB(plane_a) | MPABRA__RAMPA(plane_a); // bits 5~0
vdp2.reg.MPCDRA = MPCDRA__RAMPD(plane_a) | MPCDRA__RAMPC(plane_a); // bits 5~0
vdp2.reg.MPEFRA = MPEFRA__RAMPF(plane_a) | MPEFRA__RAMPE(plane_a); // bits 5~0
vdp2.reg.MPGHRA = MPGHRA__RAMPH(plane_a) | MPGHRA__RAMPG(plane_a); // bits 5~0
vdp2.reg.MPIJRA = MPIJRA__RAMPJ(plane_a) | MPIJRA__RAMPI(plane_a); // bits 5~0
vdp2.reg.MPKLRA = MPKLRA__RAMPL(plane_a) | MPKLRA__RAMPK(plane_a); // bits 5~0
vdp2.reg.MPMNRA = MPMNRA__RAMPN(plane_a) | MPMNRA__RAMPM(plane_a); // bits 5~0
vdp2.reg.MPOPRA = MPOPRA__RAMPP(plane_a) | MPOPRA__RAMPO(plane_a); // bits 5~0
vdp2.reg.PNCR = PNCR__R0PNB__2WORD;
vdp2.reg.RPMD = RPMD__ROTATION_PARAMETER_A;
//vdp2.reg.RPRCTL = 0;
vdp2.reg.KTCTL = 0;
vdp2.reg.KTAOF = 0;
vdp2.reg.PRIR = 3;
palette_data();
cell_data();
volatile struct vdp2_rotation_parameter_table * table = (struct vdp2_rotation_parameter_table *)&vdp2.vram.u32[0x4000 / 4];
table->screen_start_coordinate_xst = 0;
table->screen_start_coordinate_yst = 0;
table->screen_start_coordinate_zst = 0;
table->screen_vertical_coordinate_increment_dxst = 0;
table->screen_vertical_coordinate_increment_dyst = (1 << 16);
table->screen_horizontal_coordinate_increment_dx = (1 << 16);
table->screen_horizontal_coordinate_increment_dy = 0;
table->rotation_matrix_parameter_a = (-1 << 16);
table->rotation_matrix_parameter_b = 0;
table->rotation_matrix_parameter_c = 0;
table->rotation_matrix_parameter_d = 0;
table->rotation_matrix_parameter_e = (1 << 16);
table->rotation_matrix_parameter_f = 0;
table->viewpoint_coordinate_px = 0;
table->viewpoint_coordinate_py = 0;
table->viewpoint_coordinate_pz = 0;
table->center_point_coordinate_px = 0;
table->center_point_coordinate_py = 0;
table->center_point_coordinate_pz = 0;
table->horizontal_shift_mx = 0;
table->horizontal_shift_my = 0;
table->scaling_coefficient_kx = (1 << 16);
table->scaling_coefficient_ky = (1 << 16);
vdp2.reg.RPTA = (((uint32_t)table) >> 1) & 0x7ffff;
/* */
for (int i = 0; i < 64 * 64; i++) {
vdp2.vram.u32[(plane_a_offset / 4) + i] = ' ' - 0x20;
}
}
void main()
{
vdp2_init();
scu.reg.PPAF = 0; // stop execution
scu.reg.PPAF = (1 << 15) | 0; // reset PC
uint32_t * program = (uint32_t *)&_binary_scu_dsp_div10_vdp2_dsp_start;
int program_length = ((int)&_binary_scu_dsp_div10_vdp2_dsp_size) / 4;
for (int i = 0; i < program_length; i++) {
uint32_t p = program[i];
scu.reg.PPD = p;
//serial_integer(p, 8, '\n');
}
scu.reg.PPAF = (1 << 16); // execute
int end_flag = 0;
while (end_flag == 0) {
end_flag = (scu.reg.PPAF >> 18) & 1;
}
scu.reg.PPAF = 0;
scu.reg.PDA = 64 * 3; // m3[0]
serial_string("answer:\n");
for (int i = 0; i < 8; i++) {
serial_integer(scu.reg.PDD, 8, '\n');
}
serial_string("answer2:\n");
volatile uint32_t * buf = &vdp2.vram.u32[(8 * 0x4000) / 4 + 64];
for (int i = 0; i < 8; i++) {
uint32_t addr = (uint32_t)&buf[-(i + 1)];
serial_integer(addr, 8, ' ');
serial_integer(buf[-(i + 1)], 8, '\n');
}
}

5
scu-dsp/div10_vdp2.dsp.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_scu_dsp_div10_vdp2_dsp_start __asm("_binary_scu_dsp_div10_vdp2_dsp_start");
extern uint32_t _binary_scu_dsp_div10_vdp2_dsp_end __asm("_binary_scu_dsp_div10_vdp2_dsp_end");
extern uint32_t _binary_scu_dsp_div10_vdp2_dsp_size __asm("_binary_scu_dsp_div10_vdp2_dsp_size");

93
scu-dsp/parse10.asm Normal file
View File

@ -0,0 +1,93 @@
;; input m0[0] start address
;; [X ] [Y ] [D1 ]
;; mov 0,ct0
;; mov mc0,ra0
;; variables:
;; m0[0]
;; m0[1] dma read value (local); post-shift 4-byte remainder (global)
;; m0[2] saved accumulator (global)
setup:
;; [X ] [Y ] [D1 ]
mov 1,ct0
mov 0,ct3
mov 0,mc0
mov 0,mc0
mvi parse_base10,pc
mov 1,lop
;; parse_base10 return
mov all,mc3
mvi parse_base10,pc
mov 1,lop
;; parse_base10 return
mov all,mc3
nop
nop
nop
parse_base10:
;; [X ] [Y ] [D1 ]
mov 1,ct0
mov m0,p mov m0,a
add
jmp nz,parse_loop
clr a ; delay slot
dma_next_chunk:
;; dma d0,mc0,1
;; begin fake number 0x39322033 "92 3"
mvi 0x393220,pl
add mov alu,a mov 0x33,pl
rl8 mov alu,a mov 1,ct0
add mov all,mc0
;; end fake number
end_dma_next_chunk:
parse_loop:
;; extract first (leftmost) digit
mov 1,ct0
mov mc0,a mov 0x7f,pl
or
jmp s,end_of_input
rl8 mov alu,a mov 10,rx ; m0[2] 0x00000000
jmp z,dma_next_chunk
and mov m0,y mov all,pl
;; MUL: post-multiplication accumulator
;; P: post-mask digit
;; A: pre-xor string
mov 1,ct0
xor clr a mov all,mc0 ; m0[1] 0x20323300
add mov alu,a mov 0x30,pl ; 0x30 ascii '0'
;; A: post-mask digit
;;
sub mov alu,a mov 10,pl
;; if ((0x39 - 0x30) < 0) goto non_digit;
jmp s,non_digit
;; possibly set S flag for `jmp ns,non_digit`
sub mov 2,ct0 ; sub in delay slot
;; if (((0x39 - 0x30) - 10) >= 0) goto non_digit;
jmp ns,non_digit
mov mul,p mov 2,ct0 ; mov in delay slot
;; P: accumulator * 10 result
digit:
;; we have a valid digit; add it to the accumulator; save to m0[2]
;; [X ] [Y ] [D1 ]
jmp parse_loop
add mov all,mc0 ; add in delay slot ; m0[2] 0x00000009
non_digit:
;; this is not a valid digit; return and clear the accumulator as A
;; [X ] [Y ] [D1 ]
btm
mov m0,a mov 0,mc0 ; clr in delay slot ; m0[2]
;; m0:
;; 00000000 32330000 00000009 0000000
end_of_input:
btm
clr a

164
tools/ttf_bitmap2.cpp Normal file
View File

@ -0,0 +1,164 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <ft2build.h>
#include FT_FREETYPE_H
int
load_bitmap_char(FT_Face face,
FT_ULong char_code,
bool hflip,
uint8_t * buf)
{
FT_Error error;
FT_UInt glyph_index = FT_Get_Char_Index(face, char_code);
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (error) {
fprintf(stderr, "FT_Load_Glyph %s\n", FT_Error_String(error));
return -1;
}
printf("horiBearingX: %ld\n", face->glyph->metrics.horiBearingX >> 6);
printf("horiBearingY: %ld\n", face->glyph->metrics.horiBearingY >> 6);
printf("horiAdvance: %ld\n", face->glyph->metrics.horiAdvance >> 6);
printf("width: %ld\n", face->glyph->metrics.width >> 6);
printf("height: %ld\n", face->glyph->metrics.height >> 6);
assert(face->glyph->format == FT_GLYPH_FORMAT_BITMAP);
assert(face->glyph->bitmap.num_grays == 2);
for (int y = 0; y < (int)face->glyph->bitmap.rows; y++) {
uint8_t * row = &face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch];
for (int x = 0; x < (int)face->glyph->bitmap.width; x += 1) {
const int bit = (row[x / 8] >> (7 - (x % 8))) & 1;
//std::cerr << (bit ? "█" : " ");
if (hflip)
buf[y * face->glyph->bitmap.width + (7 - x)] = bit;
else
buf[y * face->glyph->bitmap.width + x] = bit;
}
//std::cerr << "|\n";
}
return face->glyph->bitmap.rows * face->glyph->bitmap.width;
}
int load_font(FT_Library * library, FT_Face * face, const char * font_file_path)
{
FT_Error error;
error = FT_Init_FreeType(library);
if (error) {
fprintf(stderr, "FT_Init_FreeType\n");
return -1;
}
error = FT_New_Face(*library, font_file_path, 0, face);
if (error) {
fprintf(stderr, "FT_New_Face\n");
return -1;
}
error = FT_Select_Size(*face, 0);
if (error) {
fprintf(stderr, "FT_Select_Size: %d: %s\n", error, FT_Error_String(error));
return -1;
}
return 0;
}
void usage(const char * argv_0)
{
printf("%s [start-hex] [end-hex] [font-width] [font-height] [hflip] [font-file-path] [output-file-path]\n", argv_0);
}
void pack_4bit(const uint8_t * src, int width, int height, int size, uint8_t * dst)
{
int offset = 0;
while (offset < size) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x += 2) {
int px0 = src[offset + y * width + x + 0];
int px1 = src[offset + y * width + x + 1];
dst[(offset / 2) + y * (width / 2) + (x / 2)] = (px0 << 4) | (px1 << 0);
}
}
offset += width * height;
}
}
int main(int argc, const char * argv[])
{
if (argc != 8) {
usage(argv[0]);
return -1;
}
char * endptr;
int start_hex = strtol(argv[1], &endptr, 16);
assert(*endptr == 0);
int end_hex = strtol(argv[2], &endptr, 16);
assert(*endptr == 0);
int font_width = strtol(argv[3], &endptr, 10);
assert(*endptr == 0);
int font_height = strtol(argv[4], &endptr, 10);
assert(*endptr == 0);
int hflip = strtol(argv[5], &endptr, 10);
assert(*endptr == 0);
assert(hflip == 0 || hflip == 1);
const char * font_file_path = argv[6];
const char * output_file_path = argv[7];
printf("start_hex %x\n", start_hex);
printf("end_hex %x\n", start_hex);
printf("font_width %d\n", font_width);
printf("font_height %d\n", font_height);
printf("font_file_path %s\n", font_file_path);
printf("output_file_path %s\n", output_file_path);
FT_Library library;
FT_Face face;
int res;
res = load_font(&library, &face, font_file_path);
if (res < 0)
return -1;
int texture_buf_size = font_width * font_height * ((end_hex - start_hex) + 1);
uint8_t * texture = (uint8_t *)malloc(texture_buf_size);
int offset = 0;
for (int char_code = start_hex; char_code <= end_hex; char_code++) {
assert(offset < texture_buf_size);
res = load_bitmap_char(face,
char_code,
hflip,
&texture[offset]);
if (res < 0)
return - 1;
assert(res == font_width * font_height);
offset += res;
}
uint8_t * pack = (uint8_t *)malloc(texture_buf_size / 2);
pack_4bit(texture, font_width, font_height, offset, pack);
FILE * out = fopen(output_file_path, "w");
if (out == NULL) {
perror("fopen(w)");
return -1;
}
//fwrite((void *)texture, texture_buf_size, 1, out);
fwrite((void *)pack, texture_buf_size / 2, 1, out);
fclose(out);
}

243
vdp1/bear.cpp Normal file
View File

@ -0,0 +1,243 @@
#include <stdint.h>
#include "vdp2.h"
#include "vdp1.h"
#include <concepts>
#include "common/vdp2_func.hpp"
#include "math/fp.hpp"
#include "math/vec3.hpp"
#include "math/mat4x4.hpp"
#include "cos.hpp"
#include "model/model.h"
#include "model/bear/material.h"
#include "model/bear/model.h"
// |--
// |
// |
using vec3 = vec<3, fp16_16>;
using mat4x4 = mat<4, 4, fp16_16>;
struct canvas {
fp16_16 width;
fp16_16 height;
};
constexpr struct canvas canvas = { 240, 240 };
template <typename T>
vec<3, T> viewport_to_canvas(T x, T y)
{
return vec<3, T>(x * canvas.width, y * canvas.height, T(1));
}
template <typename T>
inline constexpr vec<3, T> project_vertex(vec<3, T> const& v)
{
// / (v.z - T(5))
// / (v.z - T(5))
return viewport_to_canvas<T>((v.x * T(0.5) + T(2.0/3.0)),
(v.y * T(0.5) + T(0.5)));
}
constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b)
{
return ((b & 31) << 10) | ((g & 31) << 5) | ((r & 31) << 0);
}
constexpr uint16_t colors[] = {
rgb15(31, 0, 0), // red
rgb15( 0, 31, 0), // green
rgb15( 0, 0, 31), // blue
rgb15(31, 0, 31), // magenta
rgb15( 0, 31, 31), // cyan
rgb15(31, 31, 0), // yellow
};
static int32_t tick = 0;
static inline void render_quad(int ix, const vec3 a, const vec3 b, const vec3 c, const vec3 d)
{
vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYGON;
vdp1.vram.cmd[ix].LINK = 0;
vdp1.vram.cmd[ix].PMOD = PMOD__ECD | PMOD__SPD;
vdp1.vram.cmd[ix].COLR = COLR__RGB | colors[ix & 3];
vdp1.vram.cmd[ix].A.X = static_cast<int>(a.x);
vdp1.vram.cmd[ix].A.Y = static_cast<int>(a.y);
vdp1.vram.cmd[ix].B.X = static_cast<int>(b.x);
vdp1.vram.cmd[ix].B.Y = static_cast<int>(b.y);
vdp1.vram.cmd[ix].C.X = static_cast<int>(c.x);
vdp1.vram.cmd[ix].C.Y = static_cast<int>(c.y);
vdp1.vram.cmd[ix].D.X = static_cast<int>(d.x);
vdp1.vram.cmd[ix].D.Y = static_cast<int>(d.y);
}
int render_object(int ix,
const mat4x4& screen,
const struct model * model,
const struct object * object0)
{
mat4x4 trans = screen;
for (int i = 0; i < object0->quadrilateral_count; i++) {
const union quadrilateral * quad0 = &object0->quadrilateral[i];
vec3 a0 = model->position[quad0->v[0].position];
vec3 b0 = model->position[quad0->v[1].position];
vec3 c0 = model->position[quad0->v[2].position];
vec3 d0 = model->position[quad0->v[3].position];
vec3 a = trans * a0;
vec3 b = trans * b0;
vec3 c = trans * c0;
vec3 d = trans * d0;
vec3 an0 = trans * model->normal[quad0->v[0].normal];
//vec3 l = {0, 0, 1};
fp16_16 cull = dot(a, an0);
if (cull.value > 0) {
// `origin` above is p==0 below; the `origin` calculation could
// be reused, though it would hurt readability slightly
/*
for (int p = 0; p < 4; p++) {
const vec3& v0 = vertices[face[p]];
// rotation
const vec3 v1 = transform * v0;
// translation
const vec3 v2{v1.x, v1.y + fp16_16(1), v1.z + fp16_16(2)};
const vec3 v3 = project_vertex(v2 / v2.z);
}
*/
render_quad(ix,
project_vertex(a / a.z),
project_vertex(b / b.z),
project_vertex(c / c.z),
project_vertex(d / d.z));
ix++;
}
}
return ix;
}
void render()
{
tick++;
int ix = 2;
const mat4x4 scale {
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
const int rx = tick >> 2;
const mat4x4 rotationX {
1, 0, 0, 0,
0, cos(rx), sin(rx), 0,
0, -sin(rx), cos(rx), 0,
0, 0, 0, 1,
};
const int ry = tick >> 1;
const mat4x4 rotationY {
cos(ry), 0, -sin(ry), 0,
0, 1, 0, 0,
sin(ry), 0, cos(ry), 0,
0, 0, 0, 1,
};
const mat4x4 translation = {
1, 0, 0, 0,
0, 1, 0, 4.5,
0, 0, 1, 6.5,
0, 0, 0, 1,
};
const mat4x4 screen = translation * rotationY * scale;
//const vec3 camera = {0, 0, 0};
const int frame_ix0 = 0;
const struct model * model = &bear_model;
const struct object * object0 = bear_object[frame_ix0 * 2];
//const struct object * object1 = bear_object[frame_ix1 * 2];
ix = render_object(ix, screen, model, object0);
vdp1.vram.cmd[ix].CTRL = CTRL__END;
}
void main()
{
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;
// VDP2 User's Manual:
// "When sprite data is in an RGB format, sprite register 0 is selected"
// "When the value of a priority number is 0h, it is read as transparent"
//
// The power-on value of PRISA is zero. Set the priority for sprite register 0
// to some number greater than zero, so that the color data is not interpreted
// as "transparent".
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;
// the EWLR/EWRR macros use somewhat nontrivial math for the X coordinates
// 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;
// start drawing (execute the command list) on every frame
vdp1.reg.PTMR = PTMR__PTM__FRAME_CHANGE;
while (true) {
v_blank_in();
render();
}
}

189
vdp2/line_color_screen.cpp Normal file
View File

@ -0,0 +1,189 @@
/*
color data
255 colors, 3 bytes per channel, packed
*/
/*
image data
64*64 px, 1 byte per palette index
*/
#include <stdint.h>
#include "vdp2.h"
#include "../common/vdp2_func.hpp"
inline constexpr uint16_t rgb555(int r, int g, int b)
{
if (r > 255) r = 255;
if (g > 255) g = 255;
if (b > 255) b = 255;
if (r < 0) r = 0;
if (g < 0) g = 0;
if (b < 0) b = 0;
return ((b >> 3) << 10) // blue
| ((g >> 3) << 5) // green
| ((r >> 3) << 0); // red
}
template <typename T>
void fill(T * buf, T v, int32_t n) noexcept
{
while (n > 0) {
*buf++ = v;
n -= (sizeof (T));
}
}
struct color {
uint8_t r;
uint8_t g;
uint8_t b;
};
struct interp {
int line;
struct color color;
};
struct interp gradient[] = {
{ 0, {0x59, 0x6b, 0x88}},
{ 40, {0x59, 0x6b, 0x88}},
{ 80, {0xa8, 0x34, 0x14}},
{110, {0xac, 0xa5, 0x30}},
{120, {0xac, 0xa5, 0x30}},
{140, {0xa8, 0x34, 0x14}},
{999, {0xa8, 0x34, 0x14}},
};
const int gradient_len = (sizeof (gradient)) / (sizeof (gradient[0]));
struct color lerp(struct color a, struct color b, int start, int end, int y)
{
if (start == end) {
return (struct color){a.r, a.g, a.b};
}
if (end == 999) {
return (struct color){a.r, a.g, a.b};
}
int dr = ((int)b.r - (int)a.r);
int dg = ((int)b.g - (int)a.g);
int db = ((int)b.b - (int)a.b);
int t1 = end - start;
int t0 = y - start;
return (struct color){
(uint8_t)((int)a.r + dr * t0 / t1),
(uint8_t)((int)a.g + dg * t0 / t1),
(uint8_t)((int)a.b + db * t0 / t1),
};
}
void gen_gradient()
{
struct interp * prev = &gradient[0];
struct interp * cur = prev;
int i = 0;
for (int y = 0; y < 240; y++) {
if (y >= cur->line) {
prev = cur;
i += 1;
cur = &gradient[i];
}
struct color c = lerp(prev->color, cur->color, prev->line, cur->line, y);
vdp2.vram.u16[y] = rgb555(c.r, c.g, c.b);
//vdp2.vram.u16[y] = rgb555(cur->color.r, cur->color.g, cur->color.b);
}
}
void main()
{
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 2048 color
set enable "cell format" for NBG0
set character size for NBG0 to 1x1 cell */
vdp2.reg.CHCTLA = CHCTLA__N0CHCN__2048_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
*/
constexpr int plane_a = 2;
constexpr int plane_a_offset = plane_a * 0x2000;
constexpr int page_size = 64 * 64 * 2; // N0PNB__1WORD (16-bit)
constexpr int plane_size = page_size * 1;
vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 8~6
vdp2.reg.MPABN0 = MPABN0__N0MPB(plane_a) | MPABN0__N0MPA(plane_a); // bits 5~0
vdp2.reg.MPCDN0 = MPCDN0__N0MPD(plane_a) | MPCDN0__N0MPC(plane_a); // bits 5~0
constexpr int cell_size = (8 * 8) * 2; // N0CHCN__2048_COLOR (16-bit)
constexpr int character_size = cell_size * (1 * 1); // N0CHSZ__1x1_CELL
constexpr int character_offset = character_size / 0x20;
// zeroize character/cell data from 0 up to plane_a_offset
fill<uint32_t>(&vdp2.vram.u32[(0 / 2)], 0, plane_a_offset);
// "zeroize" plane_a to the 0x40th (64th) character index (an unused/transparent character)
// this creates the '40' indexes in the below picture
fill<uint16_t>(&vdp2.vram.u16[(plane_a_offset / 2)], character_offset * 0x40, plane_size);
constexpr int pixel_width = 64;
constexpr int pixel_height = 64;
constexpr int cell_horizontal = pixel_width / 8;
constexpr int cell_vertical = pixel_height / 8;
constexpr int page_width = 64;
/*
set plane_a character index data to this (hex):
|
00 01 02 03 04 05 06 07 40 40 ..
08 09 0a 0b 0c 0d 0e 0f 40 40 ..
10 11 12 13 14 15 16 17 40 40 ..
18 19 1a 1b 1c 1d 1e 1f 40 40 ..
20 21 22 23 24 25 26 27 40 40 ..
28 29 2a 2b 2c 2d 2e 2f 40 40 ..
30 31 32 33 34 35 36 37 40 40 ..
-- 38 39 3a 3b 3c 3d 3e 3f 40 40 ..
40 40 40 40 40 40 40 40 40 40 ..
40 40 40 40 40 40 40 40 40 40 ..
.. .. .. .. .. .. .. .. .. .. ..
(the above numbers are not pre-multiplied by character_offset)
*/
vdp2.reg.BKTA = BKTA__BKCLMD_PER_LINE;
gen_gradient();
}

86
vdp2/nbg0_font.cpp Normal file
View File

@ -0,0 +1,86 @@
#include <stdint.h>
#include "vdp2.h"
#include "../common/vdp2_func.hpp"
#include "font/hp_100lx_4bit.data.h"
void cell_data()
{
const uint32_t * start = reinterpret_cast<uint32_t *>(&_binary_font_hp_100lx_4bit_data_start);
const int size = reinterpret_cast<uint32_t>(&_binary_font_hp_100lx_4bit_data_size);
for (int i = 0; i < (size / 4); i++) {
vdp2.vram.u32[i] = start[i];
}
}
void palette_data()
{
vdp2.cram.u16[0] = 0x0000;
vdp2.cram.u16[1] = 0xffff;
}
void main()
{
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
| RAMCTL__VRAMD | RAMCTL__VRBMD;
vdp2.reg.VRSIZE = 0;
/* enable display of NBG0 */
vdp2.reg.BGON = BGON__N0ON | BGON__N0TPON;
/* 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;
/* 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
*/
constexpr int plane_a = 1;
constexpr int plane_a_offset = plane_a * 0x4000;
constexpr int page_size = 64 * 64 * 2; // N0PNB__1WORD (16-bit)
constexpr int plane_size = page_size * 1;
vdp2.reg.CYCA0 = 0x0F44F99F;
vdp2.reg.CYCA1 = 0x0F44F99F;
vdp2.reg.CYCB0 = 0x0F44F99F;
vdp2.reg.CYCB1 = 0x0F44F99F;
vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 8~6
vdp2.reg.MPABN0 = MPABN0__N0MPB(plane_a) | MPABN0__N0MPA(plane_a); // bits 5~0
vdp2.reg.MPCDN0 = MPCDN0__N0MPD(plane_a) | MPCDN0__N0MPC(plane_a); // bits 5~0
palette_data();
cell_data();
vdp2.reg.PNCN0 = PNCN0__N0PNB__2WORD;
for (int i = 0; i < 64 * 64; i++) {
vdp2.vram.u32[(plane_a_offset / 4) + i] = ' ' - 0x20;
}
const char * test = "conversion from 8";
int ix = 0;
while (*test) {
uint8_t c = *test++;
vdp2.vram.u32[(plane_a_offset / 4) + ix++] = c - 0x20;
}
while (1);
}

139
vdp2/rbg0_font.cpp Normal file
View File

@ -0,0 +1,139 @@
#include <stdint.h>
#include "vdp2.h"
#include "../common/vdp2_func.hpp"
#include "font/hp_100lx_4bit.data.h"
void cell_data()
{
const uint32_t * start = reinterpret_cast<uint32_t *>(&_binary_font_hp_100lx_4bit_data_start);
const int size = reinterpret_cast<uint32_t>(&_binary_font_hp_100lx_4bit_data_size);
// the start of VRAM-A0
for (int i = 0; i < (size / 4); i++) {
vdp2.vram.u32[i] = start[i];
}
}
void palette_data()
{
vdp2.cram.u16[0] = 0x0000;
vdp2.cram.u16[1] = 0xffff;
}
void main()
{
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
| RAMCTL__VRAMD
| RAMCTL__VRBMD
| RAMCTL__RDBSA0__CHARACTER_PATTERN_TABLE // VRAM-A0 0x000000
| RAMCTL__RDBSA1__PATTERN_NAME_TABLE; // VRAM-A1 0x020000
vdp2.reg.VRSIZE = 0;
/* enable display of NBG0 */
vdp2.reg.BGON = BGON__R0ON | BGON__R0TPON;
/* 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.CHCTLB = CHCTLB__R0CHCN__16_COLOR
| CHCTLB__R0BMEN__CELL_FORMAT
| CHCTLB__R0CHSZ__1x1_CELL;
/* plane size */
vdp2.reg.PLSZ = PLSZ__RAPLSZ__1x1
| PLSZ__RBPLSZ__1x1;
/* map plane offset
1-word: value of bit 6-0 * 0x2000
2-word: value of bit 5-0 * 0x4000
*/
// plane_a_offset is at the start of VRAM-A1
constexpr int plane_a = 8;
constexpr int plane_a_offset = plane_a * 0x4000;
constexpr int page_size = 64 * 64 * 2; // N0PNB__1WORD (16-bit)
constexpr int plane_size = page_size * 1;
/* cycle pattern table not used for RBG0 ? */
vdp2.reg.CYCA0 = 0x0F44F99F;
vdp2.reg.CYCA1 = 0x0F44F99F;
vdp2.reg.CYCB0 = 0x0F44F99F;
vdp2.reg.CYCB1 = 0x0F44F99F;
vdp2.reg.MPOFR = MPOFR__RAMP(0); // bits 8~6
vdp2.reg.MPABRA = MPABRA__RAMPB(plane_a) | MPABRA__RAMPA(plane_a); // bits 5~0
vdp2.reg.MPCDRA = MPCDRA__RAMPD(plane_a) | MPCDRA__RAMPC(plane_a); // bits 5~0
vdp2.reg.MPEFRA = MPEFRA__RAMPF(plane_a) | MPEFRA__RAMPE(plane_a); // bits 5~0
vdp2.reg.MPGHRA = MPGHRA__RAMPH(plane_a) | MPGHRA__RAMPG(plane_a); // bits 5~0
vdp2.reg.MPIJRA = MPIJRA__RAMPJ(plane_a) | MPIJRA__RAMPI(plane_a); // bits 5~0
vdp2.reg.MPKLRA = MPKLRA__RAMPL(plane_a) | MPKLRA__RAMPK(plane_a); // bits 5~0
vdp2.reg.MPMNRA = MPMNRA__RAMPN(plane_a) | MPMNRA__RAMPM(plane_a); // bits 5~0
vdp2.reg.MPOPRA = MPOPRA__RAMPP(plane_a) | MPOPRA__RAMPO(plane_a); // bits 5~0
vdp2.reg.PNCR = PNCR__R0PNB__2WORD;
vdp2.reg.RPMD = RPMD__ROTATION_PARAMETER_A;
//vdp2.reg.RPRCTL = 0;
vdp2.reg.KTCTL = 0;
vdp2.reg.KTAOF = 0;
vdp2.reg.PRIR = 3;
palette_data();
cell_data();
volatile struct vdp2_rotation_parameter_table * table = (struct vdp2_rotation_parameter_table *)&vdp2.vram.u32[0x4000 / 4];
table->screen_start_coordinate_xst = 0;
table->screen_start_coordinate_yst = 0;
table->screen_start_coordinate_zst = 0;
table->screen_vertical_coordinate_increment_dxst = 0;
table->screen_vertical_coordinate_increment_dyst = (1 << 16);
table->screen_horizontal_coordinate_increment_dx = (1 << 16);
table->screen_horizontal_coordinate_increment_dy = 0;
table->rotation_matrix_parameter_a = (-1 << 16);
table->rotation_matrix_parameter_b = 0;
table->rotation_matrix_parameter_c = 0;
table->rotation_matrix_parameter_d = 0;
table->rotation_matrix_parameter_e = (1 << 16);
table->rotation_matrix_parameter_f = 0;
table->viewpoint_coordinate_px = 0;
table->viewpoint_coordinate_py = 0;
table->viewpoint_coordinate_pz = 0;
table->center_point_coordinate_px = 0;
table->center_point_coordinate_py = 0;
table->center_point_coordinate_pz = 0;
table->horizontal_shift_mx = 0;
table->horizontal_shift_my = 0;
table->scaling_coefficient_kx = (1 << 16);
table->scaling_coefficient_ky = (1 << 16);
vdp2.reg.RPTA = (((uint32_t)table) >> 1) & 0x7ffff;
/* */
for (int i = 0; i < 64 * 64; i++) {
vdp2.vram.u32[(plane_a_offset / 4) + i] = ' ' - 0x20;
}
const char * test = "If sound level changes progressively, volume on 3 bit makes audi";
int ix = 0;
while (*test) {
uint8_t c = *test++;
vdp2.vram.u32[(plane_a_offset / 4) + ix++] = c - 0x20;
}
while (1);
}

170
vec4.hpp Normal file
View File

@ -0,0 +1,170 @@
#pragma once
#include "math.hpp"
#include "vec.hpp"
//
// vec4
//
template <typename T>
struct vec<4, T>
{
union {
struct { T x, y, z, w; };
struct { T a, r, g, b; };
};
inline constexpr vec();
inline constexpr vec(T scalar);
inline constexpr vec(T _x, T _y, T _z, T _w);
inline constexpr vec(const vec<3, T>& v);
constexpr inline vec<4, T> operator-() const;
inline constexpr T const& operator[](int i) const;
inline constexpr vec<4, T>& operator=(vec<4, T> const& v);
inline constexpr vec<4, T>& operator+=(vec<4, T> const& v);
inline constexpr vec<4, T>& operator-=(vec<4, T> const& v);
};
template <typename T>
inline constexpr vec<4, T>::vec()
: x(0), y(0), z(0), w(0)
{}
template <typename T>
inline constexpr vec<4, T>::vec(T scalar)
: x(scalar), y(scalar), z(scalar), w(scalar)
{}
template <typename T>
inline constexpr vec<4, T>::vec(T _x, T _y, T _z, T _w)
: x(_x), y(_y), z(_z), w(_w)
{}
template <typename T>
inline constexpr vec<4, T>::vec(const vec<3, T>& v)
: x(v.x), y(v.y), z(v.z), w(1.f)
{}
template <typename T>
constexpr inline vec<4, T> vec<4, T>::operator-() const
{
return vec<4, T>(-x, -y, -z, -w);
}
template <typename T>
inline constexpr T const& vec<4, T>::operator[](int i) const
{
switch(i)
{
default: [[fallthrough]];
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
}
template <typename T>
inline constexpr vec<4, T>& vec<4, T>::operator=(vec<4, T> const& v)
{
this->x = static_cast<T>(v.x);
this->y = static_cast<T>(v.y);
this->z = static_cast<T>(v.z);
this->w = static_cast<T>(v.w);
return *this;
}
template <typename T>
inline constexpr vec<4, T>& vec<4, T>::operator+=(vec<4, T> const& v)
{
*this = *this + vec<4, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<4, T>& vec<4, T>::operator-=(vec<4, T> const& v)
{
*this = *this - vec<4, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<4, T> operator+(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x + v2.x,
v1.y + v2.y,
v1.z + v2.z,
v1.w + v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator-(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x - v2.x,
v1.y - v2.y,
v1.z - v2.z,
v1.w - v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator*(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x * v2.x,
v1.y * v2.y,
v1.z * v2.z,
v1.w * v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator*(vec<4, T> const& v1, T const& scalar)
{
return v1 * vec<4, T>(scalar);
}
template <typename T>
inline constexpr vec<4, T> operator*(T const& scalar, vec<4, T> const& v1)
{
return vec<4, T>(scalar) * v1;
}
template <typename T>
inline constexpr vec<4, T> operator/(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x / v2.x,
v1.y / v2.y,
v1.z / v2.z,
v1.w / v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator/(vec<4, T> const& v1, T const& scalar)
{
return v1 / vec<4, T>(scalar);
}
template <typename T>
inline constexpr T dot(vec<4, T> const& v1, vec<4, T> const& v2)
{
vec<4, T> tmp(v1 * v2);
return tmp.x + tmp.y + tmp.z + tmp.w;
}
template <typename T>
inline constexpr vec<4, T> functor1(T (&func) (T const& x), vec<4, T> const& v)
{
return vec<4, T>(func(v.x), func(v.y), func(v.z), func(v.w));
}
template <typename T, typename U>
inline constexpr vec<4, U> functor1(U (&func) (T const& x), vec<4, T> const& v)
{
return vec<4, U>(func(v.x), func(v.y), func(v.z), func(v.w));
}
template <typename T>
inline constexpr T magnitude(vec<4, T> const& v)
{
return sqrt(dot(v, v));
}