diff options
| -rw-r--r-- | gb.h | 22 | ||||
| -rw-r--r-- | ops.yaml | 159 | ||||
| -rw-r--r-- | test.c | 4 | 
3 files changed, 111 insertions, 74 deletions
@@ -25,8 +25,8 @@ typedef enum {  #define GB_BTN_SELECT (1 << 6)  #define GB_BTN_START  (1 << 7) -// frame size, in bytes -#define GB_FRAME_SIZE (3 * 160 * 144) +// frame buffer size, in bytes +#define GB_FB_SIZE (3 * 160 * 144)  typedef struct gb_t_ gb_t; @@ -116,8 +116,22 @@ struct gb_t_ {              obp1,              line,              lyc; -    uint8_t rgb[GB_FRAME_SIZE]; + +    // frame buffer +    uint8_t fb[GB_FB_SIZE]; + +    // frame counter      uint32_t frame; + +    struct { +      uint8_t x, y, tile; +      bool priority, +           y_flip, +           x_flip, +           palette; +    } oam_cache[40]; + +    bool oam_dirty;    } gpu;    struct { @@ -148,7 +162,7 @@ void gb_set_buttons(gb_t * const, const uint8_t);  void gb_frame(gb_t * const);  void gb_step(gb_t * const);  _Bool gb_disasm(gb_t * const, char * const, size_t * const); -const uint8_t *gb_get_rgb_frame(const gb_t * const); +const uint8_t *gb_get_frame(const gb_t * const);  #ifdef __cplusplus  }; @@ -1890,7 +1890,7 @@ ops:          h:          c:        code: | -        mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_H)); +        mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_L));      - id: HALT        hex: 0x76        cat: misc @@ -2022,7 +2022,7 @@ ops:        cat: "8-bit load/store/move"        op: LD        dst: A -      src: L +      src: (HL)        len: 1        pc: true        time: 8 @@ -2144,7 +2144,7 @@ ops:          h: H          c: C        code: | -        add_rb(ctx, RB_H); +        add_rb(ctx, RB_L);      - id: ADD A, (HL)        hex: 0x86        cat: "8-bit math" @@ -3067,6 +3067,7 @@ ops:          h:          c:        code: | +        cpu_ww(ctx, RW_PC, old_pc + 1);          if (!FLAG(ctx, Z)) {            pop_rw(ctx, RW_PC);            clock = 20; @@ -3197,7 +3198,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x00);      - id: RET Z        hex: 0xC8 @@ -3340,7 +3341,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x08);      - id: RET NC        hex: 0xD0 @@ -3429,7 +3430,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 3); +        cpu_ww(ctx, RW_PC, old_pc + 3);          if (!FLAG(ctx, C)) {            call_a16(ctx, old_pc + 1);            clock = 24; @@ -3481,7 +3482,7 @@ ops:          h: H          c: C        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x10);      - id: RET C        hex: 0xD8 @@ -3521,8 +3522,8 @@ ops:          c:        code: |          // pop pc, enable interrupts -        pop_rw(ctx, RW_PC);          ctx->cpu.ime = true; +        pop_rw(ctx, RW_PC);      - id: JP C, a16        hex: 0xDA        cat: "jumps/calls" @@ -3612,7 +3613,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x18);      - id: LDH (a8), A        hex: 0xE0 @@ -3666,6 +3667,8 @@ ops:        hex: 0xE3        cat: "invalid"        op: XX +      code: | +        cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID);      - id: XX        hex: 0xE4        cat: "invalid" @@ -3718,7 +3721,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x20);      - id: ADD SP, r8        hex: 0xE8 @@ -3815,7 +3818,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x28);      - id: LDH A, (a8)        hex: 0xF0 @@ -3931,7 +3934,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x30);      - id: LD HL, SP+r8        hex: 0xF8 @@ -4039,7 +4042,7 @@ ops:          h:          c:        code: | -        cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); +        cpu_ww(ctx, RW_PC, old_pc + 1);          rst(ctx, 0x38);    cb: @@ -8561,6 +8564,7 @@ templates:      static void gpu_set_line(gb_t * const ctx, const uint8_t line);      static void gpu_set_mode(gb_t * const ctx, const uint8_t mode);      static bool gpu_is_active(const gb_t * const ctx); +    static uint8_t gpu_get_mode(const gb_t * const ctx);      static uint8_t      mmu_rp( @@ -8820,7 +8824,7 @@ templates:        const gb_t * const ctx,        const uint16_t addr      ) { -      switch (ctx->gpu.mode & 0x3) { +      switch (gpu_get_mode(ctx)) {        case GPU_MODE_VRAM:          return 0xFF;        default: @@ -8834,7 +8838,7 @@ templates:        const gb_t * const ctx,        const uint16_t addr      ) { -      switch (ctx->gpu.mode & 0x3) { +      switch (gpu_get_mode(ctx)) {        case GPU_MODE_HBLANK:        case GPU_MODE_VBLANK:          // oam memory (160 bytes): @@ -8954,7 +8958,7 @@ templates:        const uint16_t addr,        const uint8_t val      ) { -      switch (ctx->gpu.mode & 0x3) { +      switch (gpu_get_mode(ctx)) {        case GPU_MODE_HBLANK:        case GPU_MODE_VBLANK:        case GPU_MODE_OAM: @@ -8973,13 +8977,14 @@ templates:        const uint16_t addr,        const uint8_t val      ) { -      switch (ctx->gpu.mode & 0x3) { +      switch (gpu_get_mode(ctx) & 0x3) {        case GPU_MODE_HBLANK:        case GPU_MODE_VBLANK:          // oam memory (160 bytes):          ctx->mmu.oam[addr & 0xFF] = val; -        // TODO: invalidate OAM cache +        // invalidate oam cache +        ctx->gpu.oam_dirty = true;          break;        default: @@ -10115,7 +10120,7 @@ templates:      gpu_get_mode(        const gb_t * const ctx      ) { -      return ctx->gpu.mode & 0x3; +      return gpu_is_active(ctx) ? (ctx->gpu.mode & 0x3) : GPU_MODE_VBLANK;      }      static void @@ -10166,86 +10171,94 @@ templates:      }      static void -    gpu_draw_line( +    gpu_oam_cache(        gb_t * const ctx      ) { -      struct { -        uint8_t x, y, tile; -        bool priority, -             y_flip, -             x_flip, -             palette; -      } objs[40]; +      if (!ctx->gpu.oam_dirty) { +        return; +      }        // decode oam -      for (int i = 0; i < 40; i++) { -        objs[i].y = (ctx->mmu.oam[i * 4 + 0] + 16) & 0xFF; -        objs[i].x = (ctx->mmu.oam[i * 4 + 1] + 8) & 0xFF; -        objs[i].tile = ctx->mmu.oam[i * 4 + 2]; +      for (uint8_t i = 0; i < 40; i++) { +        ctx->gpu.oam_cache[i].y = (ctx->mmu.oam[i * 4 + 0] + 16) & 0xFF; +        ctx->gpu.oam_cache[i].x = (ctx->mmu.oam[i * 4 + 1] + 8) & 0xFF; +        ctx->gpu.oam_cache[i].tile = ctx->mmu.oam[i * 4 + 2];          const uint8_t flags = ctx->mmu.oam[i * 4 + 3]; -        objs[i].priority = flags & (1 << 7); -        objs[i].y_flip = flags & (1 << 6); -        objs[i].x_flip = flags & (1 << 5); -        objs[i].palette = flags & (1 << 4); +        ctx->gpu.oam_cache[i].priority = flags & (1 << 7); +        ctx->gpu.oam_cache[i].y_flip = flags & (1 << 6); +        ctx->gpu.oam_cache[i].x_flip = flags & (1 << 5); +        ctx->gpu.oam_cache[i].palette = flags & (1 << 4);        } +      // clear dirty flag +      ctx->gpu.oam_dirty = false; +    } + +    static void +    gpu_draw_line( +      gb_t * const ctx +    ) { +      gpu_oam_cache(ctx); +        // draw sprites behind bg -      for (int i = 0; i < 40; i++) { +      for (uint8_t i = 0; i < 40; i++) {          if (            // sprite is below bg -          objs[i].priority && +          ctx->gpu.oam_cache[i].priority &&            // sprite is on screen -          objs[i].y < 144 && objs[i].x < 160 && +          ctx->gpu.oam_cache[i].y < 144 && +          ctx->gpu.oam_cache[i].x < 160 &&            // sprite is on current line -          ctx->gpu.line >= objs[i].y && -          ctx->gpu.line <= objs[i].y +          ctx->gpu.line >= ctx->gpu.oam_cache[i].y && +          ctx->gpu.line <= ctx->gpu.oam_cache[i].y          ) { -          const uint8_t max_j = MIN(8, 160 - objs[i].x); +          const uint8_t max_j = MIN(8, 160 - ctx->gpu.oam_cache[i].x);            for (uint8_t j = 0; j < max_j; j++) { -            const uint32_t ofs = 3 * (objs[i].y * 160 + objs[i].x + j); +            const uint32_t ofs = 3 * (ctx->gpu.oam_cache[i].y * 160 + ctx->gpu.oam_cache[i].x + j);              // TODO: draw sprite scanline -            ctx->gpu.rgb[ofs + 0] = 0xff; -            ctx->gpu.rgb[ofs + 1] = 0xff; -            ctx->gpu.rgb[ofs + 2] = 0xff; +            ctx->gpu.fb[ofs + 0] = 0xff; +            ctx->gpu.fb[ofs + 1] = 0xff; +            ctx->gpu.fb[ofs + 2] = 0xff;            }          }        }        // TODO: draw background -      for (int i = 0; i < 160; i++) { +      for (uint8_t i = 0; i < 160; i++) {          // interim: set line to red -        ctx->gpu.rgb[3 * (ctx->gpu.line * 160 + i) + 0] = 0xff; -        ctx->gpu.rgb[3 * (ctx->gpu.line * 160 + i) + 1] = 0x00; -        ctx->gpu.rgb[3 * (ctx->gpu.line * 160 + i) + 2] = 0x00; +        ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 0] = 0xff; +        ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 1] = 0x00; +        ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 2] = 0x00;        }        // draw foreground sprites -      for (int i = 0; i < 40; i++) { +      for (uint8_t i = 0; i < 40; i++) {          if (            // sprite is above bg -          !objs[i].priority && +          !ctx->gpu.oam_cache[i].priority &&            // sprite is on screen -          objs[i].y < 144 && objs[i].x < 160 && +          ctx->gpu.oam_cache[i].y < 144 && +          ctx->gpu.oam_cache[i].x < 160 &&            // sprite is on current line -          ctx->gpu.line >= objs[i].y && -          ctx->gpu.line <= objs[i].y +          ctx->gpu.line >= ctx->gpu.oam_cache[i].y && +          ctx->gpu.line <= ctx->gpu.oam_cache[i].y          ) { -          const uint8_t max_j = MIN(8, 160 - objs[i].x); +          const uint8_t max_j = MIN(8, 160 - ctx->gpu.oam_cache[i].x);            for (int j = 0; j < max_j; j++) { -            const uint32_t ofs = 3 * (objs[i].y * 160 + objs[i].x + j); +            const uint32_t ofs = 3 * (ctx->gpu.oam_cache[i].y * 160 + ctx->gpu.oam_cache[i].x + j);              // TODO: draw sprite scanline -            ctx->gpu.rgb[ofs + 0] = 0xff; -            ctx->gpu.rgb[ofs + 1] = 0xff; -            ctx->gpu.rgb[ofs + 2] = 0xff; +            ctx->gpu.fb[ofs + 0] = 0xff; +            ctx->gpu.fb[ofs + 1] = 0xff; +            ctx->gpu.fb[ofs + 2] = 0xff;            }          }        } @@ -10286,7 +10299,7 @@ templates:          break;        case GPU_MODE_HBLANK:          if (ctx->gpu.clock >= 204) { -          // clear clock, draw line, increment line +          // clear clock            ctx->gpu.clock -= 204;            // draw and increment line @@ -10565,10 +10578,10 @@ templates:      }      const uint8_t * -    gb_get_rgb_frame( +    gb_get_frame(        const gb_t * const ctx      ) { -      return ctx->gpu.rgb; +      return ctx->gpu.fb;      }      static void @@ -10589,6 +10602,21 @@ templates:        cpu_set_state(ctx, 0, GB_CPU_STATE_RUN);      } +    static void +    gpu_init( +      gb_t * const ctx +    ) { +      gpu_set_mode(ctx, GPU_MODE_OAM); +      gpu_set_line(ctx, 0); +      ctx->gpu.lcdc = 0x91; +      ctx->gpu.bgp = 0xFC; +      ctx->gpu.obp0 = 0xFF; +      ctx->gpu.obp1 = 0xFF; + +      // flag oam as dirty +      ctx->gpu.oam_dirty = true; +    } +      void gb_init(        gb_t * const ctx,        const gb_config_t * const config, @@ -10609,10 +10637,5 @@ templates:        ctx->mmu.rom_size = rom_size;        // init gpu -      gpu_set_mode(ctx, GPU_MODE_OAM); -      gpu_set_line(ctx, 0); -      ctx->gpu.lcdc = 0x91; -      ctx->gpu.bgp = 0xFC; -      ctx->gpu.obp0 = 0xFF; -      ctx->gpu.obp1 = 0xFF; +      gpu_init(ctx);      } @@ -61,7 +61,7 @@ load(  }  // buffer for rendered frames -static uint8_t frames[NUM_FRAMES * GB_FRAME_SIZE]; +static uint8_t frames[NUM_FRAMES * GB_FB_SIZE];  static void  on_set_rom_bank( @@ -193,7 +193,7 @@ test_render_frames(      gb_frame(&ctx);      // copy frame to buffer -    memcpy(frames + GB_FRAME_SIZE * j, gb_get_rgb_frame(&ctx), GB_FRAME_SIZE); +    memcpy(frames + GB_FB_SIZE * j, gb_get_frame(&ctx), GB_FB_SIZE);    }    // save png  | 
