diff --git a/doc/nvidia_notes/status.xlsx b/doc/nvidia_notes/status.xlsx index 4e02b672c..b73941d31 100644 Binary files a/doc/nvidia_notes/status.xlsx and b/doc/nvidia_notes/status.xlsx differ diff --git a/src/include/86box/nv/classes/vid_nv3_classes.h b/src/include/86box/nv/classes/vid_nv3_classes.h index 5647a3c81..3b4f3b4a3 100644 --- a/src/include/86box/nv/classes/vid_nv3_classes.h +++ b/src/include/86box/nv/classes/vid_nv3_classes.h @@ -329,11 +329,8 @@ typedef struct nv3_position_32_s typedef struct nv3_object_class_001 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; // Required for NV_CLASS Core Functionality uint32_t set_notify; - uint8_t reserved2[0x1F8]; uint8_t set_beta_factor_1d31; // 31:31 (?) value, 30:21 fraction - uint8_t reserved3[0x1CFB]; // needs to be 0x2000 bytes // Put the rest of it here } nv3_beta_factor_t; @@ -371,11 +368,8 @@ typedef enum nv3_render_operation_type_e typedef struct nv3_object_class_002 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1F8]; uint8_t rop; // ROP3 (ID = ????????) - uint8_t reserved3[0x1CFB]; // needs to be 0x2000 bytes } nv3_render_operation_t; /* @@ -387,11 +381,8 @@ typedef struct nv3_object_class_002 typedef struct nv3_object_class_003 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1F8]; uint8_t color; // ROP3 (ID = ????????) - uint8_t reserved3[0x1CFB]; // needs to be 0x2000 bytes } nv3_chroma_key_t; /* @@ -403,11 +394,8 @@ typedef struct nv3_object_class_003 typedef struct nv3_object_class_004 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1F8]; uint8_t color; // ROP3 (ID = ????????) - uint8_t reserved3[0x1CFB]; // needs to be 0x2000 bytes } nv3_plane_mask_t; /* @@ -419,14 +407,11 @@ typedef struct nv3_object_class_004 typedef struct nv3_object_class_005 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0X100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1F4]; /* 16-bit precision */ nv3_position_16_t position; nv3_size_16_t size; - uint8_t reserved3[0x1CFB]; // needs to be 0x2000 bytes } nv3_clipping_rectangle_t; @@ -439,14 +424,11 @@ typedef struct nv3_object_class_005 typedef struct nv3_object_class_006 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x200]; uint32_t shape; // 0 = 8x8, 1 = 64x1, 2 = 1x64 uint32_t color0; // Some 32-bit format (argb?) uint32_t color1; // bit0=color0, bit1=color1 uint32_t pattern[2]; // bit0=color0, bit1=color1 - uint8_t reserved3[0x1CDF]; // needs to be 0x2000 bytes } nv3_pattern_t; /* @@ -458,22 +440,18 @@ typedef struct nv3_object_class_006 typedef struct nv3_object_class_007 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1FC]; uint32_t color; // The colour of the object. - uint8_t reserved3[0xF8]; - nv3_position_16_t position[16]; - nv3_size_16_t size[16]; - uint8_t reserved4[0x1B7F]; + nv3_position_16_t position[16]; // The positions of up to 16 rectangles. + nv3_size_16_t size[16]; // The sizes of up to 16 rectangles } nv3_rectangle_t; /* In case your points weren't colourful enough */ typedef struct nv3_object_class_008_cpoint_s { - nv3_color_expanded_t color; // argb-format 32-bit color - nv3_position_16_t position; // + nv3_color_expanded_t color; // argb-format 32-bit color + nv3_position_16_t position; // position } nv3_object_class_008_cpoint_t; /* @@ -485,14 +463,11 @@ typedef struct nv3_object_class_008_cpoint_s typedef struct nv3_object_class_008 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1FC]; nv3_color_expanded_t color; // argb? nv3_position_16_t point[16]; // Boring points nv3_position_32_t point32[16]; // Allows you to have points with full 32-bit precision nv3_object_class_008_cpoint_t cpoint[16]; // Allows you to have c o l o r f u l points! - uint8_t reserved3[0x1A7B]; } nv3_point_t; /* Normal line... */ @@ -525,17 +500,13 @@ typedef struct nv3_object_class_009_line32_s typedef struct nv3_object_class_009 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1FC]; nv3_color_expanded_t color; // argb? nv3_object_class_009_line_t line[16]; // List of line points (...) nv3_object_class_009_line32_t line32[8]; nv3_object_class_009_line_t polyline[32]; nv3_object_class_009_line32_t polyline32[16]; nv3_color_and_position_16_t cpolyline[16]; // List of line points and colours. - - uint8_t reserved3[0x197b]; } nv3_line_t; /* @@ -549,9 +520,9 @@ typedef struct nv3_object_class_009 typedef struct nv3_object_class_00A { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; + uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1FC]; + nv3_color_expanded_t color; // argb? nv3_object_class_009_line_t line[16]; // List of line points (...) nv3_object_class_009_line32_t line32[8]; @@ -559,7 +530,6 @@ typedef struct nv3_object_class_00A nv3_object_class_009_line32_t polyline32[16]; nv3_color_and_position_16_t cpolyline[16]; // List of line points and colours. - uint8_t reserved3[0x197b]; } nv3_lin_t; /* @@ -572,11 +542,8 @@ typedef struct nv3_object_class_00A typedef struct nv3_object_class_00B { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1FC]; nv3_color_expanded_t color; // argb? - uint8_t reserved3[0x8]; // The points of the triangle. nv3_position_16_t points[3]; @@ -592,7 +559,6 @@ typedef struct nv3_object_class_00B nv3_position_32_t mesh32[16]; nv3_color_and_position_16_t ctriangle[3]; // Triangle with colour nv3_color_and_position_16_t ctrimesh[16]; // Some kind of mesh format. I guess a list of vertex positions? with colours - uint8_t reserved4[0x19FB]; } nv3_triangle_t; /* @@ -605,31 +571,30 @@ typedef struct nv3_object_class_00B */ typedef struct nv3_object_class_00C { + /* Unclipped rect (basically class 0x07 )*/ nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x2F4]; uint32_t color_a; // Color for Clip A nv3_position_16_t rect_a_position[64]; nv3_size_16_t rect_a_size[64]; - uint8_t reserved3[0x1F0]; + /* Clipped rect */ nv3_clip_16_t clip_b; uint32_t color_b; // Color for Clip B nv3_clip_16_t clipped_rect[64]; - uint8_t reserved4[0x1E8]; + /* Unclipped transparent bitmap */ nv3_clip_16_t clip_c; uint32_t color1_c; nv3_size_16_t size_c; nv3_position_16_t point_c; uint32_t bitmap_c[128]; - uint8_t reserved5[0x368]; + /* Clipped transparent bitmap */ nv3_clip_16_t clip_d; uint32_t color1_d; nv3_size_16_t size_in_d; nv3_size_16_t size_out_d; nv3_position_16_t point_d; uint32_t bitmap_d[128]; - uint8_t reserved6[0x364]; + /* Clipped 1bpp bitmap */ nv3_clip_16_t clip_e; uint32_t color0_e; uint32_t color1_e; @@ -637,7 +602,6 @@ typedef struct nv3_object_class_00C nv3_size_16_t size_out_e; nv3_position_16_t point_e; uint32_t bitmap_e[128]; - uint8_t reserved7[0xB7F]; } nv3_win95_text_t; @@ -651,9 +615,7 @@ typedef struct nv3_object_class_00C typedef struct nv3_object_class_00D { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x204]; uint32_t offset_in; uint32_t offset_out; uint32_t pitch_in; @@ -661,9 +623,7 @@ typedef struct nv3_object_class_00D uint32_t line_length_in; // Stride? uint32_t line_count; uint8_t format; // input increment 1 2 or 4, output increment 1 2 or 4 (represented by << 8) - uint8_t reserved3[2]; uint32_t buffer_notify; // Notify the Buffedr - uint8_t reserved4[0x1CD3]; } nv3_memory_to_memory_format_t; /* @@ -676,9 +636,7 @@ typedef struct nv3_object_class_00D typedef struct nv3_object_class_00E { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x200]; nv3_position_16_t clip_0; nv3_size_16_t clip_1; nv3_position_16_t rectangle_out_0; @@ -686,7 +644,6 @@ typedef struct nv3_object_class_00E // Calculus in a graphics card uint32_t delta_du_dx; uint32_t delta_dv_dy; - uint8_t reserved3[0xE0]; nv3_size_16_t size; // can be size_y if YUV420 uint32_t pitch; uint32_t offset; @@ -697,7 +654,6 @@ typedef struct nv3_object_class_00E uint32_t offset_u; uint32_t offset_v; uint32_t point_yuv420; - uint8_t reserved4[0x1BE7]; // pad to 0x2000 } nv3_scaled_image_from_memory_t; // (0x0F does not exist) @@ -713,13 +669,10 @@ typedef struct nv3_object_class_00E typedef struct nv3_object_class_010 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x1F8]; nv3_position_16_t point_in; nv3_position_16_t point_out; nv3_size_16_t size; - uint8_t reserved3[0x1CF3]; } nv3_blit_t; /* @@ -732,15 +685,11 @@ typedef struct nv3_object_class_010 typedef struct nv3_object_class_011 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x1FC]; nv3_position_16_t point; nv3_size_16_t size; nv3_size_16_t size_in; - uint8_t reserved3[0xF0]; nv3_color_expanded_t color[32]; // The colour to use - uint8_t reserved4[0x1B7F]; } nv3_image_t; /* @@ -754,16 +703,13 @@ typedef struct nv3_object_class_011 typedef struct nv3_object_class_012 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x200]; nv3_color_expanded_t color_0; nv3_color_expanded_t color_1; nv3_position_16_t point; // Top left(?) of the bitmap nv3_size_16_t size; nv3_size_16_t size_in; uint32_t monochrome_bitmap[32]; - uint8_t reserved4[0x1B7F]; } nv3_bitmap_t; // 0x13 doesn't exist @@ -779,14 +725,11 @@ typedef struct nv3_object_class_012 typedef struct nv3_object_class_014 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x200]; nv3_position_16_t point; nv3_size_16_t size; uint32_t image_pitch; // bytes per row uint32_t image_start; - uint8_t reserved3[0x1C37]; } nv3_image_to_memory_t; /* @@ -800,17 +743,13 @@ typedef struct nv3_object_class_014 typedef struct nv3_object_class_015 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x1FC]; nv3_size_16_t size_in; uint32_t delta_dx_du; uint32_t delta_dy_dv; nv3_position_16_t clip_0; nv3_size_16_t clip_1; uint32_t point12d4; /* todo: fraction struct */ - uint8_t reserved3[0xE4]; - uint32_t color[1792]; // no reserve needed } nv3_stretched_image_from_cpu_t; @@ -1189,9 +1128,7 @@ typedef struct nv3_d3d5_coordinate_s typedef struct nv3_object_class_017 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1FC]; uint32_t texture_offset; nv3_d3d5_texture_format_t texture_format; nv3_d3d5_texture_filter_t texture_filter; @@ -1199,7 +1136,6 @@ typedef struct nv3_object_class_017 nv3_d3d5_control_out_t control_out; nv3_d3d5_alpha_control_t alpha_control; - uint8_t reserved3[0xCE4]; nv3_d3d5_coordinate_t coordinate_points[128]; // The points we are rendering. /* No placeholder needed, it really is that long. */ } nv3_d3d5_accelerated_triangle_with_zeta_buffer_t; @@ -1215,12 +1151,9 @@ typedef struct nv3_zeta_buffer_s typedef struct nv3_object_class_018 { nv3_class_ctx_switch_method_t set_notify_ctx_dma; - uint8_t reserved[0x100]; uint32_t set_notify; - uint8_t reserved2[0x1FC]; nv3_d3d5_control_out_t control_out; nv3_d3d5_alpha_control_t alpha_control; - uint8_t reserved3[0x4F0]; nv3_position_16_t point; nv3_zeta_buffer_t zeta[8]; } nv3_point_with_zeta_buffer_t; @@ -1252,13 +1185,10 @@ typedef enum nv3_object_class_01C_pixel_format_e typedef struct nv3_object_class_01C { nv3_class_ctx_switch_method_t set_notify_ctx_dma; // Set notifier context for DMA (context switch) - uint8_t reserved[0x100]; uint32_t set_notify; // Set notifier - uint8_t reserved2[0x1F8]; nv3_object_class_01C_pixel_format format; // Completely different from everything else uint32_t pitch; // 16-bit uint32_t linear_address; // 22-bit: Linear address in vram. - uint8_t reserved3[0x1C3F]; } nv3_image_in_memory_t; // See envytools. This is where we finally end up after this mess, it allows parameters to be passed to the methods. diff --git a/src/include/86box/nv/render/vid_nv3_render.h b/src/include/86box/nv/render/vid_nv3_render.h index 68bc7d557..369230347 100644 --- a/src/include/86box/nv/render/vid_nv3_render.h +++ b/src/include/86box/nv/render/vid_nv3_render.h @@ -23,21 +23,24 @@ void nv3_render_current_bpp_dfb_8(uint32_t address); void nv3_render_current_bpp_dfb_16(uint32_t address); void nv3_render_current_bpp_dfb_32(uint32_t address); +/* Pixel */ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj); uint8_t nv3_render_read_pixel_8(nv3_position_16_t position, nv3_grobj_t grobj); uint16_t nv3_render_read_pixel_16(nv3_position_16_t position, nv3_grobj_t grobj); uint32_t nv3_render_read_pixel_32(nv3_position_16_t position, nv3_grobj_t grobj); - +/* Address */ uint32_t nv3_render_get_vram_address(nv3_position_16_t position, nv3_grobj_t grobj); uint32_t nv3_render_get_vram_address_for_buffer(nv3_position_16_t position, nv3_grobj_t grobj, uint32_t buffer); -uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded); +/* Colour Conversion */ +uint32_t nv3_render_get_palette_index(uint8_t index); // Get a colour for a palette index. (The colours are 24 bit RGB888 with a 0xFF alpha added for some purposes.) +uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded); // Convert a colour to A1R10G10B10 for chroma key purposes. nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj); // Convert a colour to full RGB10 format from the current working format. uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t color); // Convert a colour from the current working format to RGB10 format. /* Pattern */ -uint32_t nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1); +void nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1); /* Primitives */ void nv3_render_rect(nv3_position_16_t position, nv3_size_16_t size, uint32_t color, nv3_grobj_t grobj); // Render an A (unclipped) GDI rect diff --git a/src/include/86box/nv/vid_nv3.h b/src/include/86box/nv/vid_nv3.h index 6d5c8cfca..5c21e1918 100644 --- a/src/include/86box/nv/vid_nv3.h +++ b/src/include/86box/nv/vid_nv3.h @@ -14,7 +14,7 @@ * Also check the doc folder for some more notres * * vid_nv3.h: NV3 Architecture Hardware Reference (open-source) - * Last updated: 6 April 2025 (STILL WORKING ON IT!!!) + * Last updated: 12 April 2025 (STILL WORKING ON IT!!!) * * Authors: Connor Hyde * @@ -727,8 +727,16 @@ extern const device_config_t nv3_config[]; #define NV3_PRAMDAC_END 0x680FFF #define NV3_PDAC_END 0x680FFF // OPTIONAL external DAC -#define NV3_VGA_DAC_START 0x6813C6 -#define NV3_VGA_DAC_END 0x6813C9 + +#define NV3_USER_DAC_START 0x681200 +#define NV3_USER_DAC_PALETTE_START 0x6813C6 +#define NV3_USER_DAC_PIXEL_MASK 0x6813C6 +#define NV3_USER_DAC_READ_MODE_ADDRESS 0x6813C7 //bit0=read/write mode? +#define NV3_USER_DAC_WRITE_MODE_ADDRESS 0x6813C8 +#define NV3_USER_DAC_PALETTE_DATA 0x6813C9 +#define NV3_USER_DAC_PALETTE_SIZE 768 +#define NV3_USER_DAC_PALETTE_END 0x6813C9 +#define NV3_USER_DAC_END 0x681FFF #define NV3_USER_START 0x800000 // Mapping for the area where objects are submitted into the FIFO (up to 0x880000?) #define NV3_USER_END 0xFFFFFF @@ -1065,6 +1073,11 @@ typedef struct nv3_pramdac_s uint32_t htotal; // horizontal total lines uint32_t hequ_width; // horizontal equ width (not sure what this is) uint32_t hserr_width; // horizontal sync error width + + uint8_t user_pixel_mask; // pixel mask for DAC lookup + uint32_t user_read_mode_address; // user read mode address + uint32_t user_write_mode_address; // user write mode address + uint8_t palette[NV3_USER_DAC_PALETTE_SIZE]; // Palette Info/CLUT - 256 entriesxr,g,b = 768 bytes } nv3_pramdac_t; /* Holds DMA channel context information */ @@ -1133,7 +1146,7 @@ typedef struct nv3_pgraph_status_s } nv3_pgraph_status_t; /* All of this B* stuff is registers at 400630..40065c and 4006a8 in reality, easier to implement it like this - BPixel = Internal Binary Representation of the pixel within the architecture + BPixel = Buffer Pixel Format */ #define NV3_BPIXEL_FORMAT 0 #define NV3_BPIXEL_FORMAT_IS_VALID 2 diff --git a/src/video/nv/nv3/nv3_core.c b/src/video/nv/nv3/nv3_core.c index 14788dcb3..e8456814f 100644 --- a/src/video/nv/nv3/nv3_core.c +++ b/src/video/nv/nv3/nv3_core.c @@ -49,9 +49,9 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv); bool nv3_is_svga_redirect_address(uint32_t addr) { - return (addr >= NV3_PRMVIO_START && addr <= NV3_PRMVIO_END) // VGA - || (addr >= NV3_PRMCIO_START && addr <= NV3_PRMCIO_END) // CRTC - || (addr >= NV3_VGA_DAC_START && addr <= NV3_VGA_DAC_END); // Legacy RAMDAC support(?) + return (addr >= NV3_PRMVIO_START && addr <= NV3_PRMVIO_END) // VGA + || (addr >= NV3_PRMCIO_START && addr <= NV3_PRMCIO_END) // CRTC + || (addr >= NV3_USER_DAC_START && addr <= NV3_USER_DAC_END); // Note: 6813c6-6813c9 are ignored somewhere else } // All MMIO regs are 32-bit i believe internally @@ -65,6 +65,14 @@ uint8_t nv3_mmio_read8(uint32_t addr, void* priv) // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. addr &= 0xFFFFFF; + // We need to specifically exclude this particular set of registers + // so we can write the 4/8bpp CLUT + if (addr >= NV3_USER_DAC_PALETTE_START && addr <= NV3_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + return nv3_mmio_arbitrate_read(addr); + } + if (nv3_is_svga_redirect_address(addr)) { // svga writes are not logged anyway rn @@ -143,6 +151,15 @@ void nv3_mmio_write8(uint32_t addr, uint8_t val, void* priv) { addr &= 0xFFFFFF; + // We need to specifically exclude this particular set of registers + // so we can write the 4/8bpp CLUT + if (addr >= NV3_USER_DAC_PALETTE_START && addr <= NV3_USER_DAC_PALETTE_END) + { + // Throw directly into PRAMDAC + nv3_mmio_arbitrate_write(addr, val); + return; + } + // This is weitek vga stuff // If we need to add more of these we can convert these to a switch statement if (nv3_is_svga_redirect_address(addr)) @@ -474,7 +491,7 @@ void nv3_pci_write(int32_t func, int32_t addr, uint8_t val, void* priv) break; default: - + break; } } @@ -493,31 +510,6 @@ void nv3_recalc_timings(svga_t* svga) svga->ma_latch += (svga->crtc[NV3_CRTC_REGISTER_RPC0] & 0x1F) << 16; - // should these actually use separate values? - // i don't we should force the top 2 bits to 1... - - // required for VESA resolutions, force parameters higher - // only fuck around with any of this in VGAmode? - - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) svga->vtotal += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) svga->vblankstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) svga->vsyncstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) svga->hdisp += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDE10)) svga->dispend += 0x400; - - if (svga->crtc[NV3_CRTC_REGISTER_HEB] & 0x01) - svga->hdisp += 0x100; // large screen bit - - /* - if (pixel_mode == NV3_CRTC_REGISTER_PIXELMODE_VGA) - { - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) svga->vtotal += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) svga->vblankstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) svga->vsyncstart += 0x400; - if (svga->crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) svga->hdisp += 0x400; - - } - */ /* Turn off override if we are in VGA mode */ svga->override = !(pixel_mode == NV3_CRTC_REGISTER_PIXELMODE_VGA); @@ -698,7 +690,7 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) addr ^= 0x60; uint8_t crtcreg = nv3->nvbase.svga.crtcreg; - uint8_t old_value; + uint8_t old_value = 0x00; // todo: // Pixel formats (8bit vs 555 vs 565) @@ -747,12 +739,33 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) case NV3_CRTC_REGISTER_RMA: nv3->pbus.rma.mode = val & NV3_CRTC_REGISTER_RMA_MODE_MAX; break; + /* Handle some large screen stuff */ + case NV3_CRTC_REGISTER_PIXELMODE: + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VDT10)) + nv3->nvbase.svga.vtotal += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VRS10)) + nv3->nvbase.svga.vblankstart += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_VBS10)) + nv3->nvbase.svga.vsyncstart += 0x400; + if (val & 1 << (NV3_CRTC_REGISTER_FORMAT_HBE6)) + nv3->nvbase.svga.hdisp += 0x400; + + /* Make sure dispend and vblankstart are right if we are displaying above 1024 vert */ + if (nv3->nvbase.svga.crtc[NV3_CRTC_REGISTER_PIXELMODE] & 1 << (NV3_CRTC_REGISTER_FORMAT_VDE10)) + nv3->nvbase.svga.dispend += 0x400; + + break; + case NV3_CRTC_REGISTER_HEB: + if (val & 0x01) + nv3->nvbase.svga.hdisp += 0x100; + break; case NV3_CRTC_REGISTER_I2C_GPIO: uint8_t scl = !!(val & 0x20); uint8_t sda = !!(val & 0x10); // Set an I2C GPIO register i2c_gpio_set(nv3->nvbase.i2c, scl, sda); break; + } /* Recalculate the timings if we actually changed them @@ -763,7 +776,7 @@ void nv3_svga_write(uint16_t addr, uint8_t val, void* priv) // and in the words of an ex-Rendition/3dfx/NVIDIA engineer, "VGA was basically an undocumented bundle of steaming you-know-what. // And it was essential that any cores the PC 3D startups acquired had to work with all the undocumented modes and timing tweaks (mode X, etc.)" if (nv3->nvbase.svga.crtcreg < 0xE - && nv3->nvbase.svga.crtcreg > 0x10) + || nv3->nvbase.svga.crtcreg > 0x10) { nv3->nvbase.svga.fullchange = changeframecount; nv3_recalc_timings(&nv3->nvbase.svga); diff --git a/src/video/nv/nv3/nv3_core_arbiter.c b/src/video/nv/nv3/nv3_core_arbiter.c index 2bb3ef8b4..99aebb5e7 100644 --- a/src/video/nv/nv3/nv3_core_arbiter.c +++ b/src/video/nv/nv3/nv3_core_arbiter.c @@ -58,9 +58,10 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address) uint32_t ret = 0x00; - // note: some registers are byte aligned not dword aligned - // only very few are though, so they can be handled specially, using the register list most likely - address &= 0xFFFFFC; + // Ensure the addresses are dword aligned. + // I don't know why this is needed because writepriv32 is always to dword align, but it crashes if you don't do this. + if (!(address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) + address &= 0xFFFFFC; // gigantic set of if statements to send the write to the right subsystem if (address >= NV3_PMC_START && address <= NV3_PMC_END) @@ -97,7 +98,8 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address) ret = nv3_prmcio_read(address); else if (address >= NV3_PVIDEO_START && address <= NV3_PVIDEO_END) ret = nv3_pvideo_read(address); - else if (address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + else if ((address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + || (address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) //clut ret = nv3_pramdac_read(address); else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END) ret = nv3_dfb_read32(address & nv3->nvbase.svga.vram_mask, &nv3->nvbase.svga); @@ -121,9 +123,12 @@ void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value) // Some of these addresses are Weitek VGA stuff and we need to mask it to this first because the weitek addresses are 8-bit aligned. address &= 0xFFFFFF; - // note: some registers are byte aligned not dword aligned - // only very few are though, so they can be handled specially, using the register list most likely - address &= 0xFFFFFC; + + // Ensure the addresses are dword aligned. + // I don't know why this is needed because writepriv32 is always to dword align, but it crashes if you don't do this. + // Exclude the 4bpp/8bpp CLUT for this purpose + if (!(address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) + address &= 0xFFFFFC; // gigantic set of if statements to send the write to the right subsystem if (address >= NV3_PMC_START && address <= NV3_PMC_END) @@ -158,7 +163,8 @@ void nv3_mmio_arbitrate_write(uint32_t address, uint32_t value) nv3_prmcio_write(address, value); else if (address >= NV3_PVIDEO_START && address <= NV3_PVIDEO_END) nv3_pvideo_write(address, value); - else if (address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + else if ((address >= NV3_PRAMDAC_START && address <= NV3_PRAMDAC_END) + || (address >= NV3_USER_DAC_PALETTE_START && address <= NV3_USER_DAC_PALETTE_END)) //clut nv3_pramdac_write(address, value); else if (address >= NV3_VRAM_START && address <= NV3_VRAM_END) nv3_dfb_write32(address, value, &nv3->nvbase.svga); diff --git a/src/video/nv/nv3/render/nv3_render_core.c b/src/video/nv/nv3/render/nv3_render_core.c index fc4bce4d9..6eb1f50c1 100644 --- a/src/video/nv/nv3/render/nv3_render_core.c +++ b/src/video/nv/nv3/render/nv3_render_core.c @@ -88,6 +88,7 @@ nv3_color_expanded_t nv3_render_expand_color(uint32_t color, nv3_grobj_t grobj) break; case nv3_pgraph_pixel_format_y8: + /* Indexed mode */ color_final.a = (color >> 8) & 0xFF; // yuv @@ -143,11 +144,11 @@ uint32_t nv3_render_downconvert_color(nv3_grobj_t grobj, nv3_color_expanded_t co packed_color |= (color.g << 20); packed_color |= (color.b << 10); break; - case nv3_pgraph_pixel_format_y8: - warning("nv3_render_downconvert: Y8 not implemented"); + case nv3_pgraph_pixel_format_y8: /* i think this is just indexed mode. since r=g=b we can just take the indexed from the r */ + packed_color = nv3_render_get_palette_index((color.r >> 2) & 0xFF); break; case nv3_pgraph_pixel_format_y16: - //warning("nv3_render_downconvert: Y16 not implemented"); + warning("nv3_render_downconvert: Y16 not implemented"); break; default: warning("nv3_render_downconvert_color unknown format %d", format); @@ -189,15 +190,24 @@ uint32_t nv3_render_to_chroma(nv3_color_expanded_t expanded) return !!expanded.a | (expanded.r << 30) | (expanded.b << 20) | (expanded.a << 10); } -/* Convert a rgb10 colour to a pattern colour */ -uint32_t nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1) +/* Get a colour for a palette index. (The colours are 24 bit RGB888 with a 0xFF alpha added for some purposes.) */ +uint32_t nv3_render_get_palette_index(uint8_t index) +{ + uint32_t red_index = index * 3; + uint32_t green_index = red_index + 1; + uint32_t blue_index = red_index + 2; + + uint8_t red_colour = nv3->pramdac.palette[red_index]; + uint8_t green_colour = nv3->pramdac.palette[green_index]; + uint8_t blue_colour = nv3->pramdac.palette[blue_index]; + + /* Alpha is always 0xFF */ + return (0xFF << 24) | ((red_colour) << 16) | ((green_colour) << 8) | blue_colour; +} + +/* Convert a rgb10 colour to a pattern colour */ +void nv3_render_set_pattern_color(nv3_color_expanded_t pattern_colour, bool use_color1) { - /* reset the colour */ - if (!use_color1) - nv3->pgraph.pattern_color_0_rgb.r = nv3->pgraph.pattern_color_0_rgb.g = nv3->pgraph.pattern_color_0_rgb.b = 0x00; - else - nv3->pgraph.pattern_color_1_rgb.r = nv3->pgraph.pattern_color_1_rgb.g = nv3->pgraph.pattern_color_1_rgb.b = 0x00; - /* select the right pattern colour, _rgb is already in RGB10 format, so we don't need to do any conversion */ if (!use_color1) @@ -359,7 +369,6 @@ uint32_t nv3_render_read_pixel_32(nv3_position_16_t position, nv3_grobj_t grobj) /* Plots a pixel. */ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grobj_t grobj) { - uint8_t alpha = 0xFF; // PFB_0 is always set to hardcoded "NO_TILING" value of 0x1114. // It seems, you are meant to @@ -372,12 +381,6 @@ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grob uint32_t framebuffer_bpp = nv3->nvbase.svga.bpp; // maybe y16 too?z - /* doesn't seem*/ - nv3_color_argb_t color_data = *(nv3_color_argb_t*)&color; - - if (framebuffer_bpp == 32) - alpha = color_data.a; - int32_t clip_end_x = nv3->pgraph.clip_start.x + nv3->pgraph.clip_size.x; int32_t clip_end_y = nv3->pgraph.clip_start.y + nv3->pgraph.clip_size.y; @@ -507,7 +510,8 @@ void nv3_render_write_pixel(nv3_position_16_t position, uint32_t color, nv3_grob /* Ensure the correct monitor size */ void nv3_render_ensure_screen_size(void) { - bool changed = false; //doesn't check if the res is the same? + /* First check if hdisp == xsize and dispend == ysize. */ + bool changed = false; if (nv3->nvbase.svga.hdisp != nv3->nvbase.svga.monitor->mon_xsize) { @@ -521,9 +525,13 @@ void nv3_render_ensure_screen_size(void) nv3->nvbase.svga.monitor->mon_ysize = nv3->nvbase.svga.dispend; } + /* + if either changed: + -> set resolution + -> set refresh rate - this is just a rough estimation right now. we need it as we only blit what changes + */ if (changed) { - /* set refresh rate - this is just a rough estimation right now. we need it as we only blit what changes */ nv3->nvbase.refresh_time = 1 / (nv3->nvbase.pixel_clock_frequency / (double)ysize / (double)xsize); // rivatimers count in microseconds set_screen_size(xsize, ysize); } @@ -534,7 +542,15 @@ void nv3_render_ensure_screen_size(void) /* Blit to the monitor from DFB, 8bpp */ void nv3_render_current_bpp_dfb_8(uint32_t address) { + nv3_size_16_t size = {0}; + size.w = size.h = 1; + nv3_position_16_t pos = nv3_render_get_dfb_position(address); + + uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); + + *p = nv3_render_get_palette_index(data & 0xFF); } /* Blit to the monitor from DFB, 15/16bpp */ @@ -545,8 +561,6 @@ void nv3_render_current_bpp_dfb_16(uint32_t address) nv3_position_16_t pos = nv3_render_get_dfb_position(address); - //pos.x >>= 1; - uint32_t* p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; uint32_t data = *(uint32_t*)&(nv3->nvbase.svga.vram[address]); @@ -623,8 +637,8 @@ void nv3_render_current_bpp(svga_t *svga, nv3_position_16_t pos, nv3_size_16_t s switch (nv3->nvbase.svga.bpp) { case 4: - /* Uh we should never be here because we're in the SVGA mode */ - fatal("NV3 - Tried to render 4bpp in NV mode"); + /* Uh we should never be here because we're in the SVGA mode(?) */ + fatal("NV3 - 4bpp not implemented (not even sure if it's SVGA only)"); break; case 8: nv3_render_8bpp(pos, size, grobj); @@ -648,7 +662,36 @@ void nv3_render_current_bpp(svga_t *svga, nv3_position_16_t pos, nv3_size_16_t s void nv3_render_8bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t grobj) { - + if (!nv3) + return; + + uint32_t vram_base; //acquired for the start of each line + uint32_t* p; + uint32_t data; + uint32_t start_x = pos.x; + + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + + for (uint32_t y = 0; y < size.h; y++) + { + /* re-set the vram address because we are basically "jumping" halfway across a line here */ + vram_base = nv3_render_get_vram_address(pos, grobj) & nv3->nvbase.svga.vram_display_mask; + + for (uint32_t x = 0; x < size.w; x++) + { + p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; + data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; + + /* should just "tip over" to the next line */ + *p = nv3_render_get_palette_index(data & 0xFF); + + vram_base++; + pos.x++; + } + + pos.x = start_x; + pos.y++; + } } /* @@ -675,7 +718,6 @@ void nv3_render_15bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t gro for (uint32_t x = 0; x < size.w; x++) { p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; /* should just "tip over" to the next line */ @@ -714,7 +756,6 @@ void nv3_render_16bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t gro for (uint32_t x = 0; x < size.w; x++) { p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; /* should just "tip over" to the next line */ @@ -750,11 +791,9 @@ void nv3_render_32bpp(nv3_position_16_t pos, nv3_size_16_t size, nv3_grobj_t gro /* re-get the vram address because we are basically "jumping" halfway across a line here */ vram_base = nv3_render_get_vram_address(pos, grobj) & nv3->nvbase.svga.vram_display_mask; - for (uint32_t x = 0; x < size.w; x++) { p = &nv3->nvbase.svga.monitor->target_buffer->line[pos.y][pos.x]; - data = *(uint32_t*)&nv3->nvbase.svga.vram[vram_base]; /* should just "tip over" to the next line */ diff --git a/src/video/nv/nv3/subsystems/nv3_pramdac.c b/src/video/nv/nv3/subsystems/nv3_pramdac.c index 5597e2f73..f9f8b670c 100644 --- a/src/video/nv/nv3/subsystems/nv3_pramdac.c +++ b/src/video/nv/nv3/subsystems/nv3_pramdac.c @@ -225,6 +225,10 @@ nv_register_t pramdac_registers[] = { NV3_PRAMDAC_HTOTAL, "PRAMDAC - Total Horizontal Lines", NULL, NULL}, { NV3_PRAMDAC_HEQU_WIDTH, "PRAMDAC - HEqu End", NULL, NULL}, { NV3_PRAMDAC_HSERR_WIDTH, "PRAMDAC - Horizontal Sync Error", NULL, NULL}, + { NV3_USER_DAC_PIXEL_MASK, "PRAMDAC - User DAC Pixel Mask", NULL, NULL}, + { NV3_USER_DAC_READ_MODE_ADDRESS, "PRAMDAC - User DAC Read Mode Address", NULL, NULL}, + { NV3_USER_DAC_WRITE_MODE_ADDRESS, "PRAMDAC - User DAC Write Mode Address", NULL, NULL}, + { NV3_USER_DAC_PALETTE_DATA, "PRAMDAC - User DAC Palette Data", NULL, NULL}, { NV_REG_LIST_END, NULL, NULL, NULL}, // sentinel value }; @@ -301,6 +305,21 @@ uint32_t nv3_pramdac_read(uint32_t address) case NV3_PRAMDAC_HSERR_WIDTH: ret = nv3->pramdac.hserr_width; break; + case NV3_USER_DAC_PIXEL_MASK: + ret = nv3->pramdac.user_pixel_mask; + break; + case NV3_USER_DAC_READ_MODE_ADDRESS: + ret = nv3->pramdac.user_read_mode_address; + break; + case NV3_USER_DAC_WRITE_MODE_ADDRESS: + ret = nv3->pramdac.user_write_mode_address; + break; + case NV3_USER_DAC_PALETTE_DATA: + /* I doubt NV actually read this in their drivers, but it's worth doing anyway */ + /* Bit 1 is listed as "read or write mode" and 7:0 as "Write-only address", but NV only ever set this to 0 too, so i think this should be fine for now */ + ret = nv3->pramdac.palette[nv3->pramdac.user_read_mode_address]; + nv3->pramdac.user_read_mode_address++; + break; } } @@ -390,8 +409,31 @@ void nv3_pramdac_write(uint32_t address, uint32_t value) nv3->pramdac.hequ_width = value; break; case NV3_PRAMDAC_HSERR_WIDTH: - nv3->pramdac.hserr_width = value; + break; + case NV3_USER_DAC_PIXEL_MASK: + nv3->pramdac.user_pixel_mask = value; + break; + case NV3_USER_DAC_READ_MODE_ADDRESS: + nv3->pramdac.user_read_mode_address = value; + break; + case NV3_USER_DAC_WRITE_MODE_ADDRESS: + + /* + This seems to get reset to 0 after 256 writes, but, the palette is 768 bytes in size. + Clearly there's some mechanism here, but I'm not sure what it is. So let's just reset if we reach 768. + */ + if (nv3->pramdac.user_write_mode_address >= NV3_USER_DAC_PALETTE_SIZE) + nv3->pramdac.user_write_mode_address = value; + + break; + case NV3_USER_DAC_PALETTE_DATA: + /* I doubt NV actually read this in their drivers, but it's worth doing anyway */ + /* Bit 1 is listed as "read or write mode" and 7:0 as "Write-only address", but NV only ever set this to 0 too, so i think this should be fine for now */ + nv3->pramdac.palette[nv3->pramdac.user_write_mode_address] = value; + + nv3->pramdac.user_write_mode_address++; + break; } } @@ -407,7 +449,3 @@ void nv3_pramdac_write(uint32_t address, uint32_t value) } } -uint32_t nv3_pramdac_read_clut(void) //4bpp/8bpp -{ - -} \ No newline at end of file