Subversion Repositories Kolibri OS

Rev

Rev 8725 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ; initalize the emulator
  2. align 4
  3. proc chip8_init stdcall
  4. ; destroys: nothing, mb flags
  5.         push    eax ecx
  6.         mov     word [P_C], 0x200
  7.         mov     word [opcode], 0
  8.         mov     word [I], 0
  9.         mov     word [S_P], 0
  10.  
  11.         ;DEBUGF  DBG_INFO, "ESP = %x\n", esp
  12.         stdcall _memset, memory, 0, MEM_SIZE
  13.         stdcall _memset, V, 0, 16
  14.         stdcall _memset, gfx, 0, GFX_SIZE
  15.         stdcall _memset, stackmem, 0, 2*STACK_SIZE ; 2 = sizeof(dw)
  16.         stdcall _memset, key, 0, KEY_SIZE
  17.         ;DEBUGF  DBG_INFO, "ESP = %x\n", esp
  18.  
  19.         mcall   66, 1 ; set scancode keyboard mode
  20.  
  21.         xor     ecx, ecx
  22. @@:
  23.         cmp     ecx, 80
  24.         jge     @f
  25.         mov     al, byte [chip8_fontset + ecx]
  26.         mov     byte [memory + FONTSET_ADDRESS + ecx], al
  27.         inc     ecx
  28.         jmp     @b
  29. @@:
  30.         mov     byte [chip8_draw_flag], 1
  31.         mov     byte [delay_timer], 0
  32.         mov     byte [sound_timer], 0
  33.         stdcall _getseed
  34.         stdcall _srand, eax
  35.  
  36.         stdcall _rand
  37.         DEBUGF  DBG_INFO, "rand() = %u\n", eax
  38.         ;stdcall _rand
  39.         ;DEBUGF  DBG_INFO, "rand() = %u\n", eax
  40.         ;stdcall _rand
  41.         ;DEBUGF  DBG_INFO, "rand() = %u\n", eax
  42.         ;stdcall _rand
  43.         ;DEBUGF  DBG_INFO, "rand() = %u\n", eax
  44.         ;stdcall _rand
  45.         ;DEBUGF  DBG_INFO, "rand() = %u\n", eax
  46.  
  47.         ;mov     word [opcode], 0xBFAF
  48.         ;movzx   eax, word [opcode]
  49.         ;mov     eax, 0xABCDEF92
  50.         ;stdcall unknown_opcode, eax
  51.         ;DEBUGF  DBG_INFO, "testprint\n"
  52.         pop     ecx eax
  53.         ret
  54. endp
  55.  
  56.  
  57. ; load game from file to memory
  58. align 4
  59. proc chip8_loadgame stdcall, struct_ptr: dword
  60. ; in: struct_ptr - pointer to structure for sysfn70
  61. ; out: ZF = 1 file loaded successfully
  62. ;      ZF = 0 error
  63. ; destroys: only flags
  64.         push    eax ebx
  65.  
  66.         mov     eax, 70
  67.         mov     ebx, [struct_ptr]
  68.         int     0x40
  69.  
  70.         cmp     eax, 0
  71.         je      @f
  72.         cmp     eax, 6
  73.         je      @f
  74.         jmp     .load_fail
  75. @@:
  76.         mov     eax, 1
  77.         jmp     .ret
  78.  
  79. .load_fail:
  80.         xor     eax, eax
  81. .ret:
  82.         test    eax, eax
  83.         pop     ebx eax
  84.         ret
  85. endp
  86.  
  87.  
  88. ; emulate one cycle
  89. align 4
  90. proc chip8_emulatecycle stdcall
  91. ; destroys: ?
  92.         locals
  93.           x     db ?
  94.           y     db ?
  95.           n     db ?
  96.           kk    db ?
  97.           nnn   dw ?
  98.         endl
  99.         ; fetch:
  100.         movzx   ecx, word [P_C]
  101.         movzx   ax, byte [memory + ecx]
  102.         shl     ax, 8
  103.         movzx   bx, byte [memory + 1 + ecx]
  104.         or      ax, bx
  105.         mov     word [opcode], ax
  106.         DEBUGF  DBG_INFO, "opcode = 0x%x, ax = 0x%x\n", [opcode]:4, ax
  107.  
  108.         shr     ax, 8
  109.         and     ax, 0x000F
  110.         mov     byte [x], al
  111.  
  112.         mov     ax, word [opcode]
  113.         shr     ax, 4
  114.         and     ax, 0x000F
  115.         mov     byte [y], al
  116.  
  117.         mov     ax, word [opcode]
  118.         and     ax, 0x000F
  119.         mov     byte [n], al
  120.  
  121.         mov     ax, word [opcode]
  122.         and     ax, 0x00FF
  123.         mov     byte [kk], al
  124.  
  125.         mov     ax, word [opcode]
  126.         and     ax, 0x0FFF
  127.         mov     word [nnn], ax
  128.  
  129.         ; DEBUGF  DBG_INFO, "P_C: 0x%x Op: 0x%x\n",  [P_C],  [opcode]:4 ; was word word
  130.         ; TODO test this and watch values of x, y, n, kk, nnn
  131.  
  132.         ; decode & execute
  133.         ; sw1
  134.         mov     ax, word [opcode]
  135.         and     ax, 0xF000
  136.  
  137.         cmp     ax, 0x0000
  138.         je      .sw1_case_0000
  139.  
  140.         cmp     ax, 0x1000
  141.         je      .sw1_case_1000
  142.  
  143.         cmp     ax, 0x2000
  144.         je      .sw1_case_2000
  145.  
  146.         cmp     ax, 0x3000
  147.         je      .sw1_case_3000
  148.  
  149.         cmp     ax, 0x4000
  150.         je      .sw1_case_4000
  151.  
  152.         cmp     ax, 0x5000
  153.         je      .sw1_case_5000
  154.  
  155.         cmp     ax, 0x6000
  156.         je      .sw1_case_6000
  157.  
  158.         cmp     ax, 0x7000
  159.         je      .sw1_case_7000
  160.  
  161.         cmp     ax, 0x8000
  162.         je      .sw1_case_8000
  163.  
  164.         cmp     ax, 0x9000
  165.         je      .sw1_case_9000
  166.  
  167.         cmp     ax, 0xA000
  168.         je      .sw1_case_A000
  169.  
  170.         cmp     ax, 0xB000
  171.         je      .sw1_case_B000
  172.  
  173.         cmp     ax, 0xC000
  174.         je      .sw1_case_C000
  175.  
  176.         cmp     ax, 0xD000
  177.         je      .sw1_case_D000
  178.  
  179.         cmp     ax, 0xE000
  180.         je      .sw1_case_E000
  181.  
  182.         cmp     ax, 0xF000
  183.         je      .sw1_case_F000
  184.  
  185.         jmp     .sw1_default
  186.  
  187. .sw1_case_0000:
  188.         ; sw2
  189.         cmp    byte [kk], 0xE0
  190.         je     .sw2_case_E0
  191.  
  192.         cmp    byte [kk], 0xEE
  193.         je     .sw2_case_EE
  194.  
  195.         jmp    .sw2_default
  196.  
  197.         .sw2_case_E0: ; clear the screen
  198.             stdcall _memset, gfx, 0, GFX_SIZE
  199.             mov     byte [chip8_draw_flag], 1
  200.             add     word [P_C], 2
  201.             jmp     .sw2_end
  202.  
  203.         .sw2_case_EE: ; TODO check!!; ret
  204.             dec     word [S_P]
  205.             movzx   ecx, word [S_P]
  206.             mov     ax, word [stackmem + ecx*2]
  207.             mov     word [P_C], ax
  208.             jmp     .sw2_end
  209.  
  210.         .sw2_default:
  211.             movzx   eax, word [opcode]
  212.             stdcall unknown_opcode, eax
  213.         .sw2_end:
  214.         jmp     .sw1_end
  215.  
  216. .sw1_case_1000: ; TODO check; 1nnn: jump to address nnn
  217.         mov     ax, word [nnn]
  218.         mov     word [P_C], ax
  219.         jmp     .sw1_end
  220.  
  221. .sw1_case_2000: ; TODO check; 2nnn: call address nnn
  222.         mov     ax, word [P_C]
  223.         add     ax, 2
  224.         movzx   ecx, word [S_P]
  225.         mov     word [stackmem + ecx*2], ax  
  226.         inc     word [S_P]
  227.         mov     ax, word [nnn]
  228.         mov     word [P_C], ax
  229.         jmp     .sw1_end
  230.  
  231. .sw1_case_3000: ; 3xkk: skip next instr if V[x] = kk
  232.         movzx   ecx, byte [x]
  233.         mov     al, byte [V + ecx]
  234.         mov     bl, byte [kk]
  235.         mov     cx, 2
  236.         cmp     al, bl
  237.         jne     @f
  238.         mov     cx, 4
  239. @@:
  240.         add     word [P_C], cx
  241.         jmp     .sw1_end
  242.  
  243. .sw1_case_4000: ; 4xkk: skip next instr if V[x] != kk
  244.         movzx   ecx, byte [x]
  245.         mov     al, byte [V + ecx]
  246.         mov     bl, byte [kk]
  247.         mov     cx, 2
  248.         cmp     al, bl
  249.         je     @f
  250.         mov     cx, 4
  251. @@:
  252.         add     word [P_C], cx
  253.         jmp     .sw1_end
  254.  
  255. .sw1_case_5000: ; 5xy0: skip next instr if V[x] == V[y]
  256.         movzx   ecx, byte [x]
  257.         mov     al, byte [V + ecx]
  258.         movzx   ecx, byte [y]
  259.         mov     bl, byte [V + ecx]
  260.         mov     cx, 2
  261.         cmp     al, bl
  262.         jne     @f
  263.         mov     cx, 4
  264. @@:
  265.         add     word [P_C], cx
  266.         jmp     .sw1_end
  267.  
  268. .sw1_case_6000: ; 6xkk: set V[x] = kk
  269.         movzx   ecx, byte [x]
  270.         mov     bl, byte [kk]
  271.         mov     byte [V + ecx], bl
  272.         add     word [P_C], 2
  273.         jmp     .sw1_end
  274.  
  275. .sw1_case_7000: ; 7xkk: set V[x] = V[x] + kk
  276.         movzx   ecx, byte [x]
  277.         mov     bl, byte [kk]
  278.         add     byte [V + ecx], bl
  279.         add     word [P_C], 2
  280.         jmp     .sw1_end
  281.  
  282. .sw1_case_8000: ; 8xyn: Arithmetic stuff
  283.         ; sw3
  284.         cmp     byte [n], 0x0
  285.         je      .sw3_case_0
  286.  
  287.         cmp     byte [n], 0x1
  288.         je      .sw3_case_1
  289.  
  290.         cmp     byte [n], 0x2
  291.         je      .sw3_case_2
  292.  
  293.         cmp     byte [n], 0x3
  294.         je      .sw3_case_3
  295.  
  296.         cmp     byte [n], 0x4
  297.         je      .sw3_case_4
  298.  
  299.         cmp     byte [n], 0x5
  300.         je      .sw3_case_5
  301.  
  302.         cmp     byte [n], 0x6
  303.         je      .sw3_case_6
  304.  
  305.         cmp     byte [n], 0x7
  306.         je      .sw3_case_7
  307.  
  308.         cmp     byte [n], 0xE
  309.         je      .sw3_case_E
  310.  
  311.         jmp     .sw3_default
  312.  
  313.         .sw3_case_0: ; V[x] = V[y]
  314.             movzx   ecx, byte [x]
  315.             movzx   edx, byte [y]
  316.             mov     al, byte [V + edx]
  317.             mov     byte [V + ecx], al
  318.             jmp     .sw3_end
  319.  
  320.         .sw3_case_1: ; V[x] = V[x] | V[y]
  321.             movzx   ecx, byte [x]
  322.             movzx   edx, byte [y]
  323.             mov     al, byte [V + ecx]
  324.             or      al, byte [V + edx]
  325.             mov     byte [V + ecx], al
  326.             jmp     .sw3_end
  327.  
  328.         .sw3_case_2: ; V[x] = V[x] & V[y]
  329.             movzx   ecx, byte [x]
  330.             movzx   edx, byte [y]
  331.             mov     al, byte [V + ecx]
  332.             and      al, byte [V + edx]
  333.             mov     byte [V + ecx], al
  334.             jmp     .sw3_end
  335.  
  336.         .sw3_case_3: ; V[x] = V[x] ^ V[y]
  337.             movzx   ecx, byte [x]
  338.             movzx   edx, byte [y]
  339.             mov     al, byte [V + ecx]
  340.             xor     al, byte [V + edx]
  341.             mov     byte [V + ecx], al
  342.             jmp     .sw3_end
  343.  
  344.         .sw3_case_4: ; V[x] = V[x] + V[y]; if carry, move 1 to V[0xF]
  345.             movzx   ecx, byte [x]
  346.             movzx   edx, byte [y]
  347.             movzx   ax, byte [V + ecx]
  348.             movzx   bx, byte [V + edx]
  349.             add     ax, bx
  350.             mov     byte [V + ecx], al
  351.  
  352.             xor     cl, cl
  353.             cmp     ax, 255
  354.             jbe     @f
  355.             inc     cl
  356.         @@:
  357.             mov     byte [V + 0xF], cl
  358.             jmp     .sw3_end
  359.  
  360.         .sw3_case_5: ;TODO check; V[x] = V[x] - V[y]; if no borrow, move 1 to V[0xF]
  361.             movzx   ecx, byte [x]
  362.             movzx   edx, byte [y]
  363.             mov     al, byte [V + ecx]
  364.             mov     bl, byte [V + edx]
  365.             sub     al, bl
  366.             mov     byte [V + ecx], al
  367.  
  368.             xor     cl, cl
  369.             cmp     al, bl
  370.             jbe     @f
  371.             inc     cl
  372.         @@:
  373.             mov     byte [V + 0xF], cl
  374.             jmp     .sw3_end
  375.  
  376.         .sw3_case_6: ; TODO check; V[x] = V[x] SHR 1 ; V[0xF] = least-significant bit of V[x] before shift
  377.             movzx   ecx, byte [x]
  378.             mov     al, byte [V + ecx]
  379.             and     al, 0x01
  380.             mov     byte [V + 0xF], al
  381.             shr     byte [V + ecx], 1
  382.             jmp     .sw3_end
  383.  
  384.         .sw3_case_7: ; TODO check; V[x] = V[y] - V[x]; if no borrow, move 1 to V[0xF]
  385.             movzx   ecx, byte [y]
  386.             movzx   edx, byte [x]
  387.             mov     al, byte [V + ecx]
  388.             mov     bl, byte [V + edx]
  389.             sub     al, bl
  390.             mov     byte [V + ecx], al
  391.  
  392.             xor     cl, cl
  393.             cmp     al, bl
  394.             jbe     @f
  395.             inc     cl
  396.         @@:
  397.             mov     byte [V + 0xF], cl
  398.             jmp     .sw3_end
  399.  
  400.         .sw3_case_E: ; TODO check; V[0xF] = most-significant bit of V[x] before shift
  401.             movzx   ecx, byte [x]
  402.             mov     al, byte [V + ecx]
  403.             shr     al, 7
  404.             and     al, 0x01
  405.             mov     byte [V + 0xF], al
  406.             shl     byte [V + ecx], 1
  407.             jmp     .sw3_end
  408.  
  409.         .sw3_default:
  410.             movzx   eax, word [opcode]
  411.             stdcall unknown_opcode, eax
  412.  
  413.         .sw3_end:
  414.         add     word [P_C], 2
  415.         jmp     .sw1_end
  416.  
  417. .sw1_case_9000: ; TODO check; 9xy0: skip instruction if V[x] != V[y]
  418.         movzx   ecx, byte [x]
  419.         mov     al, byte [V + ecx]
  420.         movzx   ecx, byte [y]
  421.         mov     bl, byte [V + ecx]
  422.         mov     cx, 2
  423.         cmp     al, bl
  424.         je      @f
  425.         mov     cx, 4
  426. @@:
  427.         add     word [P_C], cx
  428.         jmp     .sw1_end
  429.  
  430. .sw1_case_A000: ; Annn: set I to address nnn
  431.         mov     ax, word [nnn]
  432.         mov     word [I], ax
  433.         add     word [P_C], 2
  434.         jmp     .sw1_end
  435.  
  436. .sw1_case_B000: ; Bnnn: jump to location nnn + V[0]
  437.         mov     ax, word [nnn]
  438.         movzx   bx, byte [V]
  439.         add     ax, bx
  440.         mov     word [P_C], ax
  441.         jmp     .sw1_end
  442.  
  443. .sw1_case_C000: ; TODO check; Cxkk: V[x] = random byte AND kk
  444.         stdcall _rand
  445.         and     al, byte [kk]
  446.         movzx   ecx, byte [x]
  447.         mov     byte [V + ecx], al
  448.         add     word [P_C], 2
  449.         jmp     .sw1_end
  450.  
  451. .sw1_case_D000: ; TODO check; Dxyn: Display an n-byte sprite starting at memory location I at (Vx, Vy) on the screen, VF = collision
  452.         movzx   ecx, byte [x]
  453.         movzx   eax, byte [V + ecx]
  454.         movzx   ecx, byte [y]
  455.         movzx   ebx, byte [V + ecx]
  456.         movzx   ecx, byte [n]
  457.         stdcall chip8_draw_sprite, eax, ebx, ecx
  458.         mov     byte [chip8_draw_flag], 1
  459.         add     word [P_C], 2
  460.         jmp     .sw1_end
  461.  
  462. .sw1_case_E000: ; TODO check; key-pressed events
  463.         cmp    byte [kk], 0x9E
  464.         je     .sw5_case_9E
  465.  
  466.         cmp    byte [kk], 0xA1
  467.         je     .sw5_case_A1
  468.  
  469.         jmp    .sw5_default
  470.  
  471.         .sw5_case_9E: ; skip next instruction if key V[X] is pressed
  472.             movzx   ecx, byte [x]
  473.             movzx   edx, byte [V + ecx]
  474.             mov     bl, byte [key + edx]
  475.             mov     ax, 2
  476.             cmp     bl, 1
  477.             jne     .sw5_case_9E_endcheck
  478.             mov     ax, 4
  479.             mov     byte [key + edx], 0 ; release pressed key
  480.             .sw5_case_9E_endcheck:
  481.             add     word [P_C], ax
  482.             jmp     .sw5_end
  483.  
  484.         .sw5_case_A1: ; skip next instruction if key V[X] is NOT pressed
  485.             movzx   ecx, byte [x]
  486.             movzx   edx, byte [V + ecx]
  487.             mov     bl, byte [key + edx]
  488.             mov     ax, 4
  489.             cmp     bl, 1
  490.             jne     .sw5_case_A1_endcheck
  491.             mov     ax, 2
  492.             .sw5_case_A1_endcheck:
  493.             mov     byte [key + edx], 0 ; release pressed key
  494.             add     word [P_C], ax
  495.             jmp     .sw5_end
  496.  
  497.         .sw5_default:
  498.             movzx   eax, word [opcode]
  499.             stdcall unknown_opcode, eax
  500.         .sw5_end:
  501.         jmp     .sw1_end
  502.  
  503. .sw1_case_F000: ; misc
  504.         cmp    byte [kk], 0x07
  505.         je     .sw4_case_07
  506.  
  507.         cmp    byte [kk], 0x0A
  508.         je     .sw4_case_0A
  509.  
  510.         cmp    byte [kk], 0x15
  511.         je     .sw4_case_15
  512.  
  513.         cmp    byte [kk], 0x18
  514.         je     .sw4_case_18
  515.  
  516.         cmp    byte [kk], 0x1E
  517.         je     .sw4_case_1E
  518.  
  519.         cmp    byte [kk], 0x29
  520.         je     .sw4_case_29
  521.  
  522.         cmp    byte [kk], 0x33
  523.         je     .sw4_case_33
  524.  
  525.         cmp    byte [kk], 0x55
  526.         je     .sw4_case_55
  527.  
  528.         cmp    byte [kk], 0x65
  529.         je     .sw4_case_65
  530.  
  531.         jmp    .sw4_default
  532.  
  533.         .sw4_case_07: ; TODO check; V[X] = delay timer
  534.             mov     al, byte [delay_timer]
  535.             movzx   ecx, byte [x]
  536.             mov     byte [V + ecx], al
  537.             add     word [P_C], 2
  538.             jmp     .sw4_end
  539.  
  540.         .sw4_case_0A: ; TODO check; wait for key instruction
  541.             ;.sw4_case_0A_loop:
  542.                 ;mcall 2
  543.                 ;stdcall  keyboard_update, eax
  544.                 xor  ecx, ecx
  545.                 .sw4_case_0A_loop2:
  546.                     cmp  ecx, KEY_SIZE
  547.                     jae  .sw4_case_0A_loop_end ;
  548.  
  549.                     cmp  byte [key + ecx], 1
  550.                     jne  .sw4_case_0A_loop2_endcheck
  551.  
  552.                     movzx edx, byte [x]
  553.                     mov   byte [V + edx], cl
  554.                     mov  byte [key + ecx], 0 ; release pressed key
  555.                     ;jmp  .sw4_case_0A_loop_end
  556.                     add     word [P_C], 2
  557.                     jmp     .sw4_end
  558.  
  559.                     .sw4_case_0A_loop2_endcheck:
  560.                     inc  ecx
  561.                     jmp  .sw4_case_0A_loop2
  562.  
  563.             ;jmp  .sw4_case_0A_loop
  564.             .sw4_case_0A_loop_end:
  565.             ;add     word [P_C], 2
  566.             jmp     .sw4_end
  567.  
  568.         .sw4_case_15: ; TODO check; delay_timer = V[X]
  569.             movzx   ecx, byte [x]
  570.             mov     al, byte [V + ecx]
  571.             mov     byte [delay_timer], al
  572.             add     word [P_C], 2
  573.             jmp     .sw4_end
  574.  
  575.         .sw4_case_18: ; TODO check; sound_timer = V[X]
  576.             movzx   ecx, byte [x]
  577.             mov     al, byte [V + ecx]
  578.             mov     byte [sound_timer], al
  579.             add     word [P_C], 2
  580.             jmp     .sw4_end
  581.  
  582.         .sw4_case_1E: ; I = I + V[X]
  583.             ; V[0xF] = (I + V[x] > 0xfff) ? 1 : 0; (TODO?? (no this line in other chip8 emulators))
  584.             movzx   ecx, byte [x]
  585.             movzx   ax, byte [V + ecx]
  586.             add     word [I], ax
  587.             add     word [P_C], 2
  588.             jmp     .sw4_end
  589.  
  590.         .sw4_case_29: ; TODO check; I = location of font for character V[X]
  591.             movzx   ecx, byte [x]
  592.             movzx   ax, byte [V + ecx]
  593.             mov     bx, FONTSET_BYTES_PER_CHAR
  594.             mul     bx
  595.             mov     word [I], ax
  596.             add     word [P_C], 2
  597.             jmp     .sw4_end
  598.  
  599.         .sw4_case_33: ; TODO check; Store BCD for V[X] starting at address I
  600.             movzx   ecx, byte [x]
  601.             movzx   ebx, byte [V + ecx]
  602.  
  603.             stdcall mod_div, ebx, 1000, 100
  604.             movzx   ecx, word [I]
  605.             mov     byte [memory + ecx], al
  606.  
  607.             stdcall mod_div, ebx, 100, 10
  608.             mov     byte [memory + ecx + 1], al
  609.  
  610.             stdcall mod_div, ebx, 10, 1
  611.             mov     byte [memory + ecx + 2], al
  612.  
  613.             add     word [P_C], 2
  614.             jmp     .sw4_end
  615.  
  616.         .sw4_case_55: ; TODO check; Copy sprite from registers 0 to X into memory at address I
  617.             movzx   edx, word [I]
  618.             xor     ecx, ecx
  619.             .for_sw4_1:
  620.                 movzx  eax, byte [x]
  621.                 cmp    ecx, eax
  622.                 ja     .for_sw4_1_end
  623.  
  624.                 mov    al, byte [V + ecx]
  625.                 mov    byte [memory + ecx + edx], al
  626.                
  627.                 inc    ecx
  628.                 jmp    .for_sw4_1
  629.             .for_sw4_1_end:
  630.             movzx   ax, byte [x]
  631.             inc     ax
  632.             add     word [I], ax
  633.  
  634.             add     word [P_C], 2
  635.             jmp     .sw4_end
  636.  
  637.         .sw4_case_65: ; TODO check; Copy sprite from memory at address X into registers 0 to I
  638.             movzx   edx, word [I]
  639.             xor     ecx, ecx
  640.             .for_sw4_2:
  641.                 movzx  eax, byte [x]
  642.                 cmp    ecx, eax
  643.                 ja     .for_sw4_2_end
  644.  
  645.                 mov    al, byte [memory + ecx + edx]
  646.                 mov    byte [V + ecx], al
  647.  
  648.                 inc    ecx
  649.                 jmp    .for_sw4_2
  650.             .for_sw4_2_end:
  651.             movzx   ax, byte [x]
  652.             inc     ax
  653.             add     word [I], ax
  654.  
  655.             add     word [P_C], 2
  656.             jmp     .sw4_end
  657.  
  658.         .sw4_default:
  659.             movzx   eax, word [opcode]
  660.             stdcall unknown_opcode, eax
  661.         .sw4_end:
  662.         jmp     .sw1_end
  663.  
  664. .sw1_default:
  665.         movzx   eax, word [opcode]
  666.         stdcall unknown_opcode, eax
  667.  
  668. .sw1_end:
  669.         ret
  670. endp
  671.  
  672.  
  673. ; tick the timers
  674. align 4
  675. proc chip8_tick stdcall
  676. ; destroys: flags
  677.         cmp     byte [delay_timer], 0
  678.         jz      @f
  679.         dec     byte [delay_timer]
  680. @@:
  681.         cmp     byte [sound_timer], 0
  682.         jz      .ret
  683.         dec     byte [sound_timer]
  684.         cmp     byte [sound_timer], 0
  685.         jnz     @f
  686.         DEBUGF  DBG_INFO, "BEEP!\n"
  687. @@:
  688. .ret:
  689.         ret
  690. endp
  691.  
  692.  
  693. ; print unknown opcode error & exit
  694. align 4
  695. proc unknown_opcode stdcall, op:word
  696.         DEBUGF DBG_ERR, "Error: unknown opcode 0x%x\n", [op]:4
  697.         mov     eax, -1
  698.         int     0x40
  699.         ret
  700. endp
  701.  
  702. ; draw sprite from memory to gfx; TODO check;
  703. ; if collision then V[0xF] = 1
  704. align 4
  705. proc chip8_draw_sprite stdcall, col: dword, row: dword, n: dword
  706.         locals
  707.           byte_index  dd ?
  708.           bit_index   dd ?
  709.           pixelp      dd ?
  710.           temp        dd ?
  711.           _byte       db ?
  712.           _bit        db ?
  713.         endl
  714.        
  715.         DEBUGF  DBG_INFO, "draw_sprite x = %u, y = %u, n = %u\n", [col], [row], [n]
  716.  
  717.         movzx   eax, word [I]
  718.         mov     ebx, dword [memory + eax]
  719.         mov     ecx, dword [memory + eax + 4]
  720.         DEBUGF  DBG_INFO, "I = %x, at I: %x, at I + 4: %x\n", eax, ebx, ecx
  721.  
  722.         mov     byte [V + 0xF], 0
  723.         mov     dword [byte_index], 0
  724. .for1:
  725.         movzx   eax, byte [n]
  726.         cmp     dword [byte_index], eax
  727.         jae     .for1_end
  728.        
  729.         movzx   ecx, word [I]
  730.         add     ecx, dword [byte_index]
  731.         mov     al, byte [memory + ecx]
  732.         mov     byte [_byte], al
  733.         mov     dword [bit_index], 0
  734. .for2:
  735.         cmp     dword [bit_index], 8
  736.         jae     .for2_end
  737.  
  738.         mov     ecx, dword [bit_index]
  739.         mov     al, byte [_byte]
  740.         shr     al, cl
  741.         and     al, 1
  742.         mov     byte [_bit], al
  743.  
  744.         mov     eax, dword [row]
  745.         add     eax, dword [byte_index]
  746.         imul    eax, GFX_COLS
  747.         add     eax, dword [col]
  748.         add     eax, 7
  749.         sub     eax, dword [bit_index]
  750.         add     eax, gfx
  751.         mov     dword [pixelp], eax
  752.  
  753.         ; DEBUGF  DBG_INFO, "gfx = %x, pixelp = %x\n", gfx, edx
  754.  
  755.         cmp     byte [_bit], 1
  756.         jne     .if2_end
  757.  
  758.         mov     eax, dword [pixelp]
  759.         cmp     byte [eax], 1
  760.         jne     .if2_end
  761.  
  762.         mov     byte [V + 0xF], 1
  763. .if2_end:
  764.  
  765.         mov     ebx, dword [pixelp]
  766.         mov     al, byte [ebx]
  767.         xor     al, byte [_bit]
  768.         mov     byte [ebx], al
  769.  
  770.         inc     dword [bit_index]
  771.         jmp     .for2
  772. .for2_end:
  773.  
  774.         inc     dword [byte_index]
  775.         jmp     .for1
  776. .for1_end:
  777.  
  778.         ret
  779. endp
  780.