tr1p1ea wrote:
Here is some good information on the PPU: https://www.nesdev.org/wiki/PPU

I see you do have some graphics working at least, how are you handling the SDL stuff?

Thanks for the link. I took all SDL stuff out of the code, as it made little sense as it was only used for graphics and inputs. Inputs should work (graphics are preventing testing them.)
EDIT: I think there is some memory leaks, so it crashes CEmu if the LCD turns off.
Here is my current code, PPU not fast enough to work Sad . If you need to test, get your own ROM and use:
Code:
 .\convbin -i <name>.nes -o NESTESTR.8xv --iformat bin --oformat 8xv --name NESTESTR --archive
Compiled Code: https://github.com/CoolModder/NESCE/tree/main.

Code:

#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <math.h>
#include <tice.h>
#include <time.h>
#include <graphx.h>
#include <keypadc.h>
#include <inttypes.h>
#include <fileioc.h>
#include <debug.h>
#include "gfx/NESP.h"
#define PULL mem(++S, 1, 0, 0)
#define PUSH(x) mem(S--, 1, x, 1);

#define OP16(x)                                                                \
  break;                                                                       \
  case x:                                                                      \
  case x + 16:

// BGR565 palette. Used instead of RGBA32 to reduce source code size.
int scany,    // Scanline Y
    shift_at; // Attribute shift register

uint8_t *rom, *chrrom,                // Points to the start of PRG/CHR ROM
    prg[2], chr[2],                   // Current PRG/CHR banks
    A, X, Y, P = 4, S = ~2, PCH, PCL, // CPU Registers
    addr_lo, addr_hi,                 // Current instruction address
    nomem,     // 1 => current instruction doesn't write to memory
    result,    // Temp variable
    val,       // Current instruction value
    cross,     // 1 => page crossing occurred
    tmp, tmp2, // Temp variables
    ppumask, ppuctrl, ppustatus, // PPU registers
    ppubuf,                      // PPU buffered reads
    W,                           // Write toggle PPU register
    fine_x,                      // X fine scroll offset, 0..7
    opcode,                      // Current instruction opcode
    nmi,                         // 1 => NMI occurred
    ntb,                         // Nametable byte
    ptb_lo, ptb_hi,              // Pattern table low/high byte
    vram[2048],                  // Nametable RAM
    palette_ram[64],             // Palette RAM
    ram[8192],                   // CPU RAM
    chrram[8192],                // CHR RAM (only used for some games)
    prgram[8192],                // PRG RAM (only used for some games)
    oam[256],                    // Object Attribute Memory (sprite RAM)
    mask[] = {128, 64, 1, 2,     // Masks used in branch instructions
              1,   0,  0, 1, 4, 0, 0, 4, 0,
              0,   64, 0, 8, 0, 0, 8}, // Masks used in SE*/CL* instructions.
    keys,                              // Joypad shift register
    mirror,                            // Current mirroring mode
    mmc1_bits, mmc1_data, mmc1_ctrl,   // Mapper 1 (MMC1) registers
    chrbank0, chrbank1, prgbank,       // Current PRG/CHR bank
    (*rombuf)[1024 * 1024],
    *key_state;


    uint16_t T, V,           // "Loopy" PPU registers
        sum,                 // Sum used for ADC/SBC
        dot,                 // Horizontal position of PPU, from 0..340
        atb,                 // Attribute byte
        shift_hi, shift_lo,  // Pattern table shift registers
        cycles;              // Cycle count for current instruction
   

// Read a byte from CHR ROM or CHR RAM.
uint8_t *get_chr_byte(uint16_t a) {
  return &chrrom[chr[a >> 12] << 12 | a & 4095];
}

// Read a byte from nametable RAM.
uint8_t *get_nametable_byte(uint16_t a) {
  return &vram[!mirror       ? a % 1024                  // single bank 0
               : mirror == 1 ? a % 1024 + 1024           // single bank 1
               : mirror == 2 ? a & 2047                  // vertical mirroring
                             : a / 2 & 1024 | a % 1024]; // horizontal mirroring
}

// If `write` is non-zero, writes `val` to the address `hi:lo`, otherwise reads
// a value from the address `hi:lo`.
uint8_t mem(uint8_t lo, uint8_t hi, uint8_t val, uint8_t write) {
  uint16_t a = hi << 8 | lo;

  switch (hi >> 4) {
  case 0 ... 1: // $0000...$1fff RAM
    return write ? ram[a] = val : ram[a];

  case 2 ... 3: // $2000..$2007 PPU (mirrored)
    lo &= 7;

    // read/write $2007
    if (lo == 7) {
      tmp = ppubuf;
      uint8_t *rom =
          // Access CHR ROM or CHR RAM
          V < 8192 ? !write || chrrom == chrram ? get_chr_byte(V) : &tmp2
          // Access nametable RAM
          : V < 16128 ? get_nametable_byte(V)
                      // Access palette RAM
                      : palette_ram + (uint8_t)((V & 19) == 16 ? V ^ 16 : V);
      write ? *rom = val : (ppubuf = *rom);
      V += ppuctrl & 4 ? 32 : 1;
      V %= 16384;
      return tmp;
    }

    if (write)
      switch (lo) {
      case 0: // $2000 ppuctrl
        ppuctrl = val;
        T = T & 62463 | val % 4 << 10;
        break;

      case 1: // $2001 ppumask
        ppumask = val;
        break;

      case 5: // $2005 ppuscroll
        T = (W ^= 1)      ? fine_x = val & 7,
        T & ~31 | val / 8 : T & 35871 | val % 8 << 12 | (val & 248) * 4;
        break;

      case 6: // $2006 ppuaddr
        T = (W ^= 1) ? T & 255 | val % 64 << 8 : (V = T & ~255 | val);
      }

    if (lo == 2) // $2002 ppustatus
      return tmp = ppustatus & 224, ppustatus &= 127, W = 0, tmp;

    break;

  case 4:
    if (write && lo == 20) // $4014 OAM DMA
      for (sum = 256; sum--;)
        oam[sum] = mem(sum, val, 0, 0);
    // $4016 Joypad 1
    return (lo == 22) ? write ? keys = ((kb_Data[7] & kb_Right) * 8 +
                                        (kb_Data[7] & kb_Left) * 4 +
                                        (kb_Data[7] & kb_Down) * 2 +
                                        (kb_Data[7] & kb_Up)) *
                                           16 +
                                        (kb_Data[6] & kb_Clear) * 8 +
                                        (kb_Data[5] & kb_Vars) * 4 +
                                        (kb_2nd & kb_Data[1]) * 2 +
                                        (kb_Alpha & kb_Data[2])
                              : (tmp = keys & 1, keys /= 2, tmp)
                      : 0;

  case 6 ... 7: // $6000...$7fff PRG RAM
    return write ? prgram[a & 8191] = val : prgram[a & 8191];

  case 8 ... 15: // $8000...$ffff ROM
    // handle mmc1 writes
    if (write)
      switch ((*rombuf)[6] >> 4) {
      case 7: // mapper 7
        mirror = !(val / 16);
        *prg = val = val % 8 * 2;
        prg[1] = val + 1;
        break;

      case 3: // mapper 3
        *chr = val = val % 4 * 2;
        chr[1] = val + 1;
        break;

      case 2: // mapper 2
        *prg = val & 31;
        break;

      case 1: // mapper 1
        if (val & 128) {
          mmc1_bits = 5, mmc1_data = 0, mmc1_ctrl |= 12;
        } else if (mmc1_data = mmc1_data / 2 | val << 4 & 16, !--mmc1_bits) {
          mmc1_bits = 5, tmp = a >> 13;
          *(tmp == 4 ? mirror = mmc1_data & 3, &mmc1_ctrl
        : tmp == 5   ? &chrbank0
        : tmp == 6   ? &chrbank1
                     : &prgbank) = mmc1_data;

          // Update CHR banks.
          *chr = chrbank0 & ~!(mmc1_ctrl & 16);
          chr[1] = mmc1_ctrl & 16 ? chrbank1 : chrbank0 | 1;

          // Update PRG banks.
          tmp = mmc1_ctrl / 4 & 3;
          *prg = tmp == 2 ? 0 : tmp == 3 ? prgbank : prgbank & ~1;
          prg[1] = tmp == 2 ? prgbank : tmp == 3 ? (*rombuf)[4] - 1 : prgbank | 1;
        }
      }
    return rom[prg[(a >> 14) - 2] << 14 | a & 16383];
  }

  return ~0;
}

// Read a byte at address `PCH:PCL` and increment PC.
uint8_t read_pc() {
  val = mem(PCL, PCH, 0, 0);
  !++PCL ? ++PCH : 0;
  return val;
}

// Set N (negative) and Z (zero) flags of `P` register, based on `val`.
uint8_t set_nz(uint8_t val) { return P = P & ~130 | val & 128 | !val * 2; }

int main(void) {
  uint8_t var = ti_Open("NESTESTR", "r");
  if (var == 0)
  {
      os_SetCursorPos(0, 0);
      os_PutStrFull("ERROR OPENING NESTEST");
      while (!os_GetCSC());
      exit(0);

  }
  if (NESP_init == 0)
  {
      os_SetCursorPos(0, 0);
      os_PutStrFull("MISSING PALETTE");
      while (!os_GetCSC());
      exit(0);

  }
  rombuf = ti_GetDataPtr(var);
  ti_Close(var);
 
  // Start PRG0 after 16-byte header.
  rom = *rombuf + 16;
  // PRG1 is the last bank. `rombuf[4]` is the number of 16k PRG banks.
  prg[1] = (*rombuf)[4] - 1;
  // CHR0 ROM is after all PRG data in the file. `rombuf[5]` is the number of
  // 8k CHR banks. If it is zero, assume the game uses CHR RAM.
  chrrom = (*rombuf)[5] ? rom + ((prg[1] + 1) << 14) : chrram;
  // CHR1 is the last 4k bank.
  chr[1] = ((*rombuf)[5] ? (*rombuf)[5] : 1) * 2 - 1;
  // Bit 0 of `rombuf[6]` is 0=>horizontal mirroring, 1=>vertical mirroring.
  mirror = !((*rombuf)[6] & 1) + 2;

  // Start at address in reset vector, at $FFFC.
  PCL = mem(~3, ~0, 0, 0);
  PCH = mem(~2, ~0, 0, 0);

  gfx_Begin();
  gfx_SetDrawBuffer(); // draw to the buffer to avoid rendering artifacts
 

  gfx_ZeroScreen();

  for (;;) {
    cycles = nomem = 0;
    if (nmi)
      goto nmi;
    kb_Scan();
    if (kb_Data[1] & kb_Del)
    {
        break;
    }
    switch ((opcode = read_pc()) & 31) {
    case 0:
      dbg_printf("Case 0", dot);
      if (opcode & 128) { // LDY/CPY/CPX imm
        read_pc();
        nomem = 1;
        goto nomemop;
      }

      switch (opcode >> 5) {
      case 0: // BRK or NMI
        !++PCL ? ++PCH : 0;
      nmi:
        PUSH(PCH)
        PUSH(PCL)
        PUSH(P | 32)
        // BRK vector is $ffff, NMI vector is $fffa
        PCL = mem(~1 - nmi * 4, ~0, 0, 0);
        PCH = mem(~0 - nmi * 4, ~0, 0, 0);
        cycles++;
        nmi = 0;
        break;

      case 1: // JSR
        result = read_pc();
        PUSH(PCH)
        PUSH(PCL)
        PCH = read_pc();
        PCL = result;
        break;

      case 2: // RTI
        P = PULL & ~32;
        PCL = PULL;
        PCH = PULL;
        break;

      case 3: // RTS
        PCL = PULL;
        PCH = PULL;
        !++PCL ? ++PCH : 0;
        break;
      }

      cycles += 4;
      break;

    case 16: // BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ
      read_pc();
      if (!(P & mask[opcode >> 6 & 3]) ^ opcode / 32 & 1) {
        if (cross = PCL + (int8_t)val >> 8)
          PCH += cross, cycles++;
        cycles++, PCL += (int)val;
      }
           dbg_printf("Case 16", dot);
    OP16(8)
      dbg_printf("OP16 8", dot);
      switch (opcode >>= 4) {
      case 0: // PHP
        PUSH(P | 48)
        cycles++;
        break;

      case 2: // PLP
        P = PULL & ~16;
        cycles += 2;
        break;

      case 4: // PHA
        PUSH(A)
        cycles++;
        break;

      case 6: // PLA
        set_nz(A = PULL);
        cycles += 2;
        break;

      case 8: // DEY
        set_nz(--Y);
        break;

      case 9: // TYA
        set_nz(A = Y);
        break;

      case 10: // TAY
        set_nz(Y = A);
        break;

      case 12: // INY
        set_nz(++Y);
        break;

      case 14: // INX
        set_nz(++X);
        break;

      default: // CLC, SEC, CLI, SEI, CLV, CLD, SED
        P = P & ~mask[opcode + 3] | mask[opcode + 4];
        break;
      }

    OP16(10)
      dbg_printf("OP16 10", dot);
      switch (opcode >> 4) {
      case 8: // TXA
        set_nz(A = X);
        break;

      case 9: // TXS
        S = X;
        break;

      case 10: // TAX
        set_nz(X = A);
        break;

      case 11: // TSX
        set_nz(X = S);
        break;

      case 12: // DEX
        set_nz(--X);
        break;

      case 14: // NOP
        break;

      default: // ASL/ROL/LSR/ROR A
        nomem = 1;
        val = A;
        goto nomemop;
      }
      break;

    case 1: // X-indexed, indirect
      read_pc();
      val += X;
      addr_lo = mem(val, 0, 0, 0);
      addr_hi = mem(val + 1, 0, 0, 0);
      cycles += 4;
      goto opcode;

    case 4 ... 6: // Zeropage
      addr_lo = read_pc();
      addr_hi = 0;
      cycles++;
      goto opcode;

    case 2: case 9: // Immediate
      read_pc();
      nomem = 1;
      goto nomemop;

    case 12 ... 14: // Absolute
      addr_lo = read_pc();
      addr_hi = read_pc();
      cycles += 2;
      goto opcode;

    case 17: // Zeropage, Y-indexed
      addr_lo = mem(read_pc(), 0, 0, 0);
      addr_hi = mem(val + 1, 0, 0, 0);
      val = Y;
      tmp = opcode == 145; // STA always uses extra cycle.
      cycles++;
      goto cross;

    case 20 ... 22: // Zeropage, X-indexed
      addr_lo = read_pc() + ((opcode & 214) == 150 ? Y : X); // LDX/STX use Y
      addr_hi = 0;
      cycles += 2;
      goto opcode;

    case 25: // Absolute, Y-indexed.
      addr_lo = read_pc();
      addr_hi = read_pc();
      val = Y;
      tmp = opcode == 153; // STA always uses extra cycle.
      goto cross;

    case 28 ... 30: // Absolute, X-indexed.
      addr_lo = read_pc();
      addr_hi = read_pc();
      val = opcode == 190 ? Y : X; // LDX uses Y
      tmp = opcode == 157 ||      // STA always uses extra cycle.
                              // ASL/ROL/LSR/ROR/INC/DEC all uses extra cycle.
             opcode % 16 == 14 && opcode != 190;
      // fallthrough
    cross:
      addr_hi += cross = addr_lo + val > 255;
      addr_lo += val;
      cycles += 2 + tmp | cross;
      // fallthrough

    opcode:
      // Read from the given address into `val` for convenience below, except
      // for the STA/STX/STY instructions, and JMP.
      (opcode & 224) != 128 &&opcode != 76 ? val = mem(addr_lo, addr_hi, 0, 0)
                                           : 0;
     
    nomemop:
      switch (opcode & 243) {
      OP16(1) set_nz(A |= val);  // ORA
      OP16(33) set_nz(A &= val); // AND
      OP16(65) set_nz(A ^= val); // EOR

      OP16(225) // SBC
        val = ~val;
        goto add;

      OP16(97) // ADC
      add:
        sum = A + val + (P & 1);
        P = P & ~65 | sum > 255 | (~(A ^ val) & (val ^ sum) & 128) / 2;
        set_nz(A = sum);

      OP16(2) // ASL
        result = val * 2;
        P = P & ~1 | val / 128;
        goto memop;

      OP16(34) // ROL
        result = val * 2 | P & 1;
        P = P & ~1 | val / 128;
        goto memop;

      OP16(66) // LSR
        result = val / 2;
        P = P & ~1 | val & 1;
        goto memop;

      OP16(98) // ROR
        result = val / 2 | P << 7;
        P = P & ~1 | val & 1;
        goto memop;

      OP16(194) // DEC
        result = val - 1;
        goto memop;

      OP16(226) // INC
        result = val + 1;
        // fallthrough

      memop:
        set_nz(result);
        // Write result to A or back to memory.
        nomem ? A = result : (cycles += 2, mem(addr_lo, addr_hi, result, 1));
        break;

      case 32: // BIT
        P = P & 61 | val & 192 | !(A & val) * 2;
        break;

      case 64: // JMP
        PCL = addr_lo;
        PCH = addr_hi;
        cycles--;
        break;

      case 96: // JMP indirect
        PCL = val;
        PCH = mem(addr_lo + 1, addr_hi, 0, 0);
        cycles++;

      OP16(160) set_nz(Y = val); // LDY
      OP16(161) set_nz(A = val); // LDA
      OP16(162) set_nz(X = val); // LDX

      OP16(128) result = Y; goto store; // STY
      OP16(129) result = A; goto store; // STA
      OP16(130) result = X;             // STX

      store:
        mem(addr_lo, addr_hi, result, 1);

      OP16(192) result = Y; goto cmp; // CPY
      OP16(193) result = A; goto cmp; // CMP
      OP16(224) result = X;           // CPX
      cmp:
        P = P & ~1 | result >= val;
        set_nz(result - val);
        break;
      }
    }

    // Update PPU, which runs 3 times faster than CPU. Each CPU instruction
    // takes at least 2 cycles.
    for (tmp = cycles * 3 + 6; tmp--;) {
      if (ppumask & 24) { // If background or sprites are enabled.
        if (scany < 240) {
          if (dot < 256 || dot > 319) {
            switch (dot & 7) {
            case 1: // Read nametable byte.
              ntb = *get_nametable_byte(V);
              break;
            case 3: // Read attribute byte.
              atb = (*get_nametable_byte(960 | V & 3072 | V >> 4 & 56 |
                                         V / 4 & 7) >>
                     (V >> 5 & 2 | V / 2 & 1) * 2) &
                    3;
              atb |= atb * 4;
              atb |= atb << 4;
              atb |= atb << 8;
              break;
            case 5: // Read pattern table low byte.
              ptb_lo = *get_chr_byte(ppuctrl << 8 & 4096 | ntb << 4 | V >> 12);
              break;
            case 7: // Read pattern table high byte.
              ptb_hi =
                  *get_chr_byte(ppuctrl << 8 & 4096 | ntb << 4 | V >> 12 | 8);
              // Increment horizontal VRAM read address.
              V = (V & 31) == 31 ? V & ~31 ^ 1024 : V + 1;
              break;
            }

            // Draw a pixel to the framebuffer.
            if ((uint16_t)scany < 240 && dot < 256) {
              // Read color and palette from shift registers.
              uint8_t color = shift_hi >> 14 - fine_x & 2 |
                              shift_lo >> 15 - fine_x & 1,
                      palette_temp = shift_at >> 28 - fine_x * 2 & 12;

              // If sprites are enabled.
              if (ppumask & 16)
                // Loop through all sprites.
                for (uint8_t *sprite = oam; sprite < oam + 256; sprite += 4) {
                  uint16_t sprite_h = ppuctrl & 32 ? 16 : 8,
                           sprite_x = dot - sprite[3],
                           sprite_y = scany - *sprite - 1,
                           sx = sprite_x ^ (sprite[2] & 64 ? 0 : 7),
                           sy = sprite_y ^ (sprite[2] & 128 ? sprite_h - 1 : 0);
                  if (sprite_x < 8 && sprite_y < sprite_h) {
                    uint16_t sprite_tile = sprite[1],
                             sprite_addr = ppuctrl & 32
                                               // 8x16 sprites
                                               ? sprite_tile % 2 << 12 |
                                                     (sprite_tile & ~1) << 4 |
                                                     (sy & 8) * 2 | sy & 7
                                               // 8x8 sprites
                                               : (ppuctrl & 8) << 9 |
                                                     sprite_tile << 4 | sy & 7,
                             sprite_color =
                                 *get_chr_byte(sprite_addr + 8) >> sx << 1 & 2 |
                                 *get_chr_byte(sprite_addr) >> sx & 1;
                    // Only draw sprite if color is not 0 (transparent)
                    if (sprite_color) {
                      // Don't draw sprite if BG has priority.
                      !(sprite[2] & 32 && color)
                          ? color = sprite_color,
                            palette_temp = 16 | sprite[2] * 4 & 12 : 0;
                      // Maybe set sprite0 hit flag.
                      sprite == oam &&color ? ppustatus |= 64 : 0;
                      break;
                    }
                  }
                }
              gfx_SetColor(palette_ram[color ? palette_temp | color : 0]);
              // Write pixel to framebuffer. Always use palette 0 for color 0.
              gfx_SetPixel(dot + 32, scany);
            }

            // Update shift registers every cycle.
            dot < 336 ? shift_hi *= 2, shift_lo *= 2, shift_at *= 4 : 0;

            // Reload shift registers every 8 cycles.
            dot % 8 == 7        ? shift_hi |= ptb_hi, shift_lo |= ptb_lo,
                shift_at |= atb : 0;
          }

          // Increment vertical VRAM address.
          dot == 256 ? V = ((V & 7 << 12) != 7 << 12 ? V + 4096
                            : (V & 992) == 928       ? V & 35871 ^ 2048
                            : (V & 992) == 992       ? V & 35871
                                               : V & 35871 | V + 32 & 992) &
                               // Reset horizontal VRAM address to T value.
                               ~1055 |
                           T & 1055
                     : 0;
        }

        // Reset vertical VRAM address to T value.
        scany == -1 &&dot > 279 &&dot < 305 ? V = V & 33823 | T & 31712 : 0;
      }

      if (scany == 241 && dot == 1) {
        // If NMI is enabled, trigger NMI.
        ppuctrl & 128 ? nmi = 1 : 0;
        ppustatus |= 128;
        gfx_BlitBuffer();
        dbg_printf("Draw", dot);

      }

      // Clear ppustatus.
      scany == -1 &&dot == 1 ? ppustatus = 0 : 0;

      // Increment to next dot/scany. 341 dots per scanline, 262 scanlines per
      // frame. Scanline 261 is represented as -1.
      ++dot == 341 ? dot = 0, scany = scany == 260 ? -1 : scany + 1 : 0;
    }
  }
  gfx_End();
  exit(0);
}
Picture:

What it should be:

EDIT: Looks like GFX is using default palette instead of the custom one.
I'm honestly shocked someone decided to try this. But I'm also glad, because someone had to do it eventually. Incredible work so far.
Centered view:
CoolModder wrote:

EDIT: Looks like GFX is using default palette instead of the custom one.


This might be a dumb question, but have you tried loading the costume palette? Overall, well done. The code looks a bit scary, though. Do you mind uploading it to GitHub instead of Cemetech?
Alvajoy123 wrote:
CoolModder wrote:

EDIT: Looks like GFX is using default palette instead of the custom one.


This might be a dumb question, but have you tried loading the costume palette? Overall, well done. The code looks a bit scary, though. Do you mind uploading it to GitHub instead of Cemetech?

Did I... *Realizes I forgot parentheses at the end* ...No, I didn't. Will upload to Github tomorrow. Also, this is based off of an existing emulator.
Can't wait to play Mach Rider and R.C. Pro-Am II on my calc in Geometry class.
Check this out: https://www.cemetech.net/forum/viewtopic.php?t=17953&start=0
This guy got the rendering down. I think you could probably make yours even faster than his, although some assembly required.
Video of rendering: (100% Speed, Palette still not working)

Edit: Appears the CPU runs for a little bit, then the PPU runs and the CPU stops. Code uploading to github.
Is there any way to optimize setting pixels to a color?
EDIT: Will see if I can write new code that uses lines instead of setting each pixel by itself. (I actually have no idea how it works, so, no, I will not.)
I don't know exactly how one would optimize that, but I do appreciate being able to see it render now. Does the CPU run while it's rendering? I believe you could try to cut everything except inputs out of the time that it's rendering. There's no audio, so there could be some optimization there too. I'm not super familiar with the NES internals (despite owning one myself and having to clean it occasionally), so this is just a suggestion. I do know that the CPU stuff could definitely be optimized with a bit of Assembly. I would totally try doing it myself if the Linux container wasn't screwed up on my Chromebook (fingers crossed I get a Pi 5 for Christmas).
TL;DR: C is fast, but not fast enough. Use some Assembly here and there.
jasper7474 wrote:
TL;DR: C is fast, but not fast enough. Use some Assembly here and there.

Or (hear me out here) this will never be feasible past a proof of concept as I stated years ago.
MateoConLechuga wrote:
jasper7474 wrote:
TL;DR: C is fast, but not fast enough. Use some Assembly here and there.

Or (hear me out here) this will never be feasible past a proof of concept as I stated years ago.

I don't think so. With enough assembly, tradeoffs, and determination, it can happen. I would be happy if it played at half or one-third speed.
jasper7474 wrote:
MateoConLechuga wrote:
jasper7474 wrote:
TL;DR: C is fast, but not fast enough. Use some Assembly here and there.

Or (hear me out here) this will never be feasible past a proof of concept as I stated years ago.

I don't think so. With enough assembly, tradeoffs, and determination, it can happen. I would be happy if it played at half or one-third speed.

Not possible. It's not going to happen - best possible is maybe 3 frames per second.
MateoConLechuga wrote:
jasper7474 wrote:
MateoConLechuga wrote:
jasper7474 wrote:
TL;DR: C is fast, but not fast enough. Use some Assembly here and there.

Or (hear me out here) this will never be feasible past a proof of concept as I stated years ago.

I don't think so. With enough assembly, tradeoffs, and determination, it can happen. I would be happy if it played at half or one-third speed.

Not possible. It's not going to happen - best possible is maybe 3 frames per second.

Okay, fine. You're probably right; although many said that GB Color emulation was going to be impossible, and now I can play Super Mario Bros. DX on my calculator.
jasper7474 wrote:
Okay, fine. You're probably right; although many said that GB Color emulation was going to be impossible, and now I can play Super Mario Bros. DX on my calculator.

I don't know of anyone who said that, so now you're just making things up.
I uploaded a more recent version of my code to the github. The one with copy is an older version. I am attempting to set up the use of lines instead of individual pixels.
Hmm so far, the code is quite scary (needs refactoring), I noticed there is a missing file that handles graphics, `"gfx/NESP.h"` I also have no idea how you convert ROMs to .8xv, could you explain?
Alvajoy123 wrote:
Hmm so far, the code is quite scary (needs refactoring), I noticed there is a missing file that handles graphics, `"gfx/NESP.h"` I also have no idea how you convert ROMs to .8xp, could you explain?

Rom Conversion: Go to the Toolchain's bin folder and run:[ code] .\convbin -i <name>.nes -o NESTESTR.8xv --iformat bin --oformat 8xv --name NESTESTR --archive[/code] Will upload NESP.h and c tomorrow.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 2 of 3
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement