line_count[0] = line_count[1] = 0;
vert_line_count = -1;
display_linebuf = 0;
+ render_linebuf = 0;
r50_planemask = 0x0f;
r50_pagesel = 0;
{
__UNLIKELY_IF(dst == nullptr) return false;
- int trans = (display_linebuf == 0) ? display_linebuf_mask : ((display_linebuf - 1) & display_linebuf_mask);
+ int trans = display_linebuf & display_linebuf_mask;
// int trans = display_linebuf & 3;
int magx = linebuffers[trans][y].mag[layer];
int pwidth = linebuffers[trans][y].pixels[layer];
{
// 256 colors
__UNLIKELY_IF(dst == nullptr) return false;
- int trans = (display_linebuf == 0) ? display_linebuf_mask : ((display_linebuf - 1) & display_linebuf_mask);
+ int trans = display_linebuf & display_linebuf_mask;
// int trans = display_linebuf & 3;
int magx = linebuffers[trans][y].mag[0];
int pwidth = linebuffers[trans][y].pixels[0];
{
__UNLIKELY_IF(dst == nullptr) return false;
- int trans = (display_linebuf == 0) ? display_linebuf_mask : ((display_linebuf - 1) & display_linebuf_mask);
+ int trans = display_linebuf & display_linebuf_mask;
// int trans = display_linebuf & 3;
int magx = linebuffers[trans][y].mag[layer];
int pwidth = linebuffers[trans][y].pixels[layer];
__UNLIKELY_IF(width > TOWNS_CRTC_MAX_PIXELS) width = TOWNS_CRTC_MAX_PIXELS;
__UNLIKELY_IF(width <= 0) return;
- int trans = (display_linebuf == 0) ? display_linebuf_mask : ((display_linebuf - 1) & display_linebuf_mask);
+ int trans = display_linebuf & display_linebuf_mask;
int bitshift0 = linebuffers[trans][y].bitshift[0];
int bitshift1 = linebuffers[trans][y].bitshift[1];
void TOWNS_CRTC::draw_screen()
{
- int trans = (display_linebuf == 0) ? display_linebuf_mask : ((display_linebuf - 1) & display_linebuf_mask);
+ int trans = display_linebuf & display_linebuf_mask;
//int trans2 = ((display_linebuf - 2) & display_linebuf_mask);
bool do_alpha = false; // ToDo: Hardware alpha rendaring.
__UNLIKELY_IF(d_vram == nullptr) {
// }
mix_screen(y, width, do_mix0, do_mix1);
}
-
- //display_linebuf = (display_linebuf + 1) & 3;
return;
}
prio = voutreg_prio;
//int trans = (display_linebuf - 1) & 3;
- int trans = display_linebuf & display_linebuf_mask;
+ int trans = render_linebuf & display_linebuf_mask;
__UNLIKELY_IF(linebuffers[trans] == nullptr) return;
__DECL_VECTORIZED_LOOP
offset = (offset + ((-bit_shift) >> ashift)) & (((ctrl & 0x10) == 0) ? 0x7ffff : 0x3ffff);
offset = offset + (int)head_address[l];
offset <<= ashift;
-// bit_shift = _x >> ashift;
- if((trans & 1) != 0) offset = offset + (frame_offset_bak[l] <<= ashift);
+ if((trans & 1) != 0) offset = offset + (frame_offset_bak[l] << ashift);
+// if((trans & 1) != 0) offset = offset + (frame_offset[l] << ashift);
if(l == 1) {
- offset = offset + (fo1_offset_value <<= ashift);
- }
- if(linebuffers[trans][line].mode[l] == DISPMODE_16) {
+ offset = offset + (fo1_offset_value << ashift);
+ }
+ //! Note:
+ //! - Below is from Tsugaru, commit 1a442831 .
+ //! - I wonder sprite offset effects every display mode at page1,
+ //! and FMR's address offset register effects every display mode at page0
+ //! - -- 20230715 K.O
+ if(l == 0) {
offset += ((page_16mode != 0) ? 0x20000 : 0);
- }
- if(l == 1) {
- if((is_sprite) && (linebuffers[trans][line].mode[l] == DISPMODE_32768)) {
- offset += sprite_offset;
- }
+ } else {
+ offset += sprite_offset;
}
offset = offset & address_mask[l]; // OK?
offset += address_add[l];
zoom_count_vert[l] = zoom_factor_vert[l];
// ToDo: Interlace
if(to_disp[l]) {
- head_address[l] += line_offset_bak[l];
+ //head_address[l] += line_offset_bak[l];
+ head_address[l] += line_offset[l];
}
}
}
void TOWNS_CRTC::event_pre_frame()
{
+ display_linebuf = render_linebuf & display_linebuf_mask; // Incremant per vstart
interlace_field = !interlace_field;
for(int i = 0; i < 2; i++) {
crtout_top[i] = crtout[i];
void TOWNS_CRTC::event_frame()
{
- display_linebuf = (display_linebuf + 1) & display_linebuf_mask; // Incremant per vstart
- hst[display_linebuf] = hst_tmp;
- vst[display_linebuf] = vst_tmp;
+ render_linebuf = (render_linebuf + 1) & display_linebuf_mask; // Incremant per vstart
+ hst[render_linebuf] = hst_tmp;
+ vst[render_linebuf] = vst_tmp;
lines_per_frame = max_lines;
line_count[0] = line_count[1] = 0;
vert_line_count = -1;
hsync = false;
- //! @note at event_pre_frame() at SPRITE, clear VRAM if enabled.
+ //! @note Every event_pre_frame() at SPRITE, clear VRAM if enabled.
is_sprite = (d_sprite->read_signal(SIG_TOWNS_SPRITE_ENABLED) != 0) ? true : false;
- if(is_sprite) {
- sprite_offset = (d_sprite->read_signal(SIG_TOWNS_SPRITE_DISP_PAGE1) != 0) ? 0x20000 : 0x00000;
- } else {
- sprite_offset = 0x00000;
- }
+ //! Note:
+ //! - Below is from Tsugaru, commit 1a442831 .
+ //! - I wonder sprite offset effects every display mode at page1.
+ //! - -- 20230715 K.O
+ sprite_offset = (d_sprite->read_signal(SIG_TOWNS_SPRITE_DISP_PAGE1) != 0) ? 0x20000 : 0x00000;
// ToDo: EET
//register_event(this, EVENT_CRTC_VSTART, frame_us, false, &event_id_frame); // EVENT_VSTART MOVED TO event_frame().
cancel_event_by_id(event_id_vst1);
hst[i] = hst_tmp;
}
display_linebuf = 0;
+ render_linebuf = 0;
req_recalc = false;
force_recalc_crtc_param();
}
#ifndef _TOWNS_CRTC_H_
#define _TOWNS_CRTC_H_
+#include <atomic>
#include "device.h"
-
#include "towns_common.h"
/*
* I/O Address :
* #28 has bit 15,14 and 7 to 0.
* #29 has 4bit.
* #31 has bit15 and bit 8 to 0.
- *
+ *
* #00 / bit 7 - 1 : HSW1 (Bit 10 to 8 and 0 must be '0')
* #01 / bit 7 - 1 : HSW2 (Bit 10 to 8 and 0 must be '0')
* #02 / ??
* #14 / bit10 - 0 : VDE0 (Layer 0)
* #15 / bit10 - 0 : VDS1 (Layer 1)
* #16 / bit10 - 0 : VDE1 (Layer 1)
- * #17 / bit15 - 0 : FA0 (Layer 0)
- * #18 / bit10 - 0 : HAJ0 (Layer 0)
- * #19 / bit15 - 0 : FO0 (Layer 0)
- * #20 / bit15 - 0 : LO0 (Layer 0)
- * #21 / bit15 - 0 : FA1 (Layer 1)
- * #22 / bit10 - 0 : HAJ1 (Layer 1)
- * #23 / bit15 - 0 : FO1 (Layer 1)
+ * #17 / bit15 - 0 : FA0 (Layer 0)
+ * #18 / bit10 - 0 : HAJ0 (Layer 0)
+ * #19 / bit15 - 0 : FO0 (Layer 0)
+ * #20 / bit15 - 0 : LO0 (Layer 0)
+ * #21 / bit15 - 0 : FA1 (Layer 1)
+ * #22 / bit10 - 0 : HAJ1 (Layer 1)
+ * #23 / bit15 - 0 : FO1 (Layer 1)
* #24 / bit15 - 0 : LO1 (Layer 1)
* #25 / bit10 - 0 : EHAJ (External horizonal sync adjusting)
* #26 / bit10 - 0 : EVAJ (External horizonal sync adjusting)
* bit1-0 : CL0
* #29 / bit3-2 : SCSEL (Clock divide = 2 * (SCSEL + 1)).
* bit1-0 : CLKSEL (00 = 28.6363MHz / 01 = 24.5454MHz / 10 = 25.175MHz / 11 = 21.0525MHz)
- * #30 / Status register (RO):
+ * #30 / Status register (RO):
* bit15 : DSPTV1 / bit14 : DSPTV0 (VDISP = '1')
* bit13 : DSPTH1 / bit12 : DSPTH0 (HDISP = '1')
* bit11 : FIELD (Field number)
TOWNS_CRTC_REG_VST1,
TOWNS_CRTC_REG_VST2,
TOWNS_CRTC_REG_EET,
-
+
TOWNS_CRTC_REG_VST, // 8
TOWNS_CRTC_REG_HDS0,
TOWNS_CRTC_REG_HDE0,
TOWNS_CRTC_REG_VDS0,
TOWNS_CRTC_REG_VDE0,
TOWNS_CRTC_REG_VDS1,
-
+
TOWNS_CRTC_REG_VDE1,
TOWNS_CRTC_REG_FA0,
TOWNS_CRTC_REG_HAJ0,
TOWNS_CRTC_REG_FA1,
TOWNS_CRTC_REG_HAJ1,
TOWNS_CRTC_REG_FO1,
-
+
TOWNS_CRTC_REG_LO1,
TOWNS_CRTC_REG_EHAJ,
TOWNS_CRTC_REG_EVAJ,
#pragma pack(push, 1)
uint8_t r50_planemask; // MMIO 000CF882h : BIT 5(C0) and BIT2 to 0
uint8_t crtout[2];
- uint8_t r50_pad;
+ uint8_t r50_pad;
#pragma pack(pop)
int32_t bitshift[2];
uint32_t pad;
TOWNS_VRAM* d_vram;
TOWNS_SPRITE* d_sprite;
FONT_ROMS* d_font;
-
+
uint16_t machine_id;
uint8_t cpu_id;
bool is_compatible;
bool address_changed[2];
bool mode_changed[2];
uint32_t fo1_offset_value;
-
+
uint8_t display_mode[2];
bool line_changed[2][TOWNS_CRTC_MAX_LINES];
bool display_enabled;
-
+
double crtc_clock; //
int cpu_clocks;
-
+
// They are not saved.Must be calculate when loading.
double horiz_us; // (HST + 1) * clock
double horiz_width_posi_us, horiz_width_nega_us; // HSW1, HSW2
double vst2_us;
int hst[4], vst[4];
int vst_tmp, hst_tmp;
-
+
double vert_start_us[2];
double vert_end_us[2];
double horiz_start_us[2];
double horiz_end_us[2];
-
+
bool req_recalc;
// End
uint32_t hend_words[2]; // HEND ((HDE[01] * clock) : Horizonal offset words (Related by ZH[01]). Maybe 0.
uint32_t frame_offset[2]; // FOx.
uint32_t line_offset[2]; // LOx.
-
+
uint32_t frame_offset_bak[2]; // FOx(Backup).
uint32_t line_offset_bak[2]; // LOx(Backup).
-
+
uint32_t head_address[2];
int horiz_offset_tmp[2];
int vert_offset_tmp[2];
bool is_sprite;
uint32_t sprite_offset;
-
+
uint8_t zoom_factor_vert[2]; // Related display resolutions of two layers and zoom factors.
uint8_t zoom_factor_horiz[2]; // Related display resolutions of two layers and zoom factors.
uint8_t zoom_count_vert[2];
uint8_t scsel;
uint8_t clksel;
-
+
int pixels_per_line;
int lines_per_frame;
int max_lines;
-
+
int vert_line_count; // Not separate per layer.Total count.
// Note: To display to real screen, use blending of OpenGL/DirectX
// from below framebuffers per layer if you can.
// And, recommand to use (hardware) shader to rendering (= not to use framebuffer of below) if enabled.
// Not recommanded to use draw_screen() type rendering.
// Rendering precesses may be heavily to use only CPU (I think). 20170107 K.Ohta.
-
+
// Not Saved?.
// End.
bool vsync, hsync, hdisp[2], frame_in[2];
bool interlace_field;
-
-
+
+
// Around Analog palette.
uint8_t apalette_code; // I/O FD90H (RW). 16 or 256 colors.
uint8_t apalette_b; // I/O FD92H (RW).
scrntype_t apalette_256_pixel[256]; // Not saved. Must be calculated.
uint8_t tvram_snapshot[0x4000];
-
+
// FM-R50 emulation
uint8_t r50_planemask; // MMIO 000CF882h : BIT 5(C0) and BIT2 to 0
uint8_t r50_pagesel; // MMIO 000CF882h : BIT 4
uint8_t dpalette_regs[8]; // I/O FD98H - FD9FH
bool dpalette_changed;
-
+
// Video output controller (I/O 0448H, 044AH)
// Register 00 : Display mode.
// Register 11: Priority mode.
bool video_brightness; // false = high.
-
+
// Others.
// VRAM CONTROL REGISTER.
uint8_t voutreg_num; // I/O 0448h
uint8_t crtout_reg;
// End.
-
- //
+
+ //
// Event IDs. Saved.
int event_id_hsync;
int event_id_hsw;
int event_id_hds[2];
int event_id_hde[2];
- int display_linebuf;
+ std::atomic<int> display_linebuf;
+ std::atomic<int> render_linebuf;
int display_linebuf_mask;
-
+
__DECL_ALIGNED(32) linebuffer_t linebuffers[4][TOWNS_CRTC_MAX_LINES];
// Render buffer
void restart_display();
void stop_display();
void notify_mode_changed(int layer, uint8_t mode);
-
+
void cancel_event_by_id(int& event_num);
-
+
void set_crtc_clock(uint16_t val);
uint16_t read_reg30();
uint32_t __FASTCALL get_font_address(uint32_t c, uint8_t &attr);
-
+
virtual void __FASTCALL calc_apalette16(int layer, int index);
virtual void __FASTCALL calc_apalette256(int index);
virtual void __FASTCALL calc_apalette(int index);
-
+
virtual void __FASTCALL set_apalette_r(uint8_t val);
virtual void __FASTCALL set_apalette_g(uint8_t val);
virtual void __FASTCALL set_apalette_b(uint8_t val);
virtual uint8_t __FASTCALL get_apalette_b();
virtual uint8_t __FASTCALL get_apalette_r();
virtual uint8_t __FASTCALL get_apalette_g();
-
+
bool __FASTCALL render_16(scrntype_t* dst, scrntype_t *mask, scrntype_t* pal, int y, int layer, bool do_alpha);
bool __FASTCALL render_256(scrntype_t* dst, int y);
bool __FASTCALL render_32768(scrntype_t* dst, scrntype_t *mask, int y, int layer, bool do_alpha);
void update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame);
void event_pre_frame();
void event_frame();
-
+
void __FASTCALL write_signal(int id, uint32_t data, uint32_t mask);
uint32_t __FASTCALL read_signal(int ch);
void __FASTCALL write_io8(uint32_t addr, uint32_t data);
void __FASTCALL write_io16(uint32_t addr, uint32_t data);
uint32_t __FASTCALL read_io16(uint32_t addr);
-
+
void __FASTCALL event_callback(int event_id, int err);
bool process_state(FILEIO* state_fio, bool loading);
__UNLIKELY_IF(line >= TOWNS_CRTC_MAX_LINES) return NULL;
return &(linebuffers[page][line]);
}
-
+
void set_context_sprite(DEVICE* dev)
{
d_sprite = (TOWNS_SPRITE*)dev;
{
cpu_id = val & 0x07;
}
-
+
void set_context_vsync(DEVICE* device, int id, uint32_t mask)
{
register_output_signal(&outputs_int_vsync, device, id, mask);
}
#endif
-