1

Тема: Приклад писаної мовою FASM демки для архітектури CHIP-8

Додав до клясичного FASM`у (окрім нього існує новий форк FASM G, який взагалі не вміє кодувати жодну архітектуру) систему команд архітектури CHIP-8, всі мнемоніки cкопіював з керівництва Cowgod`а (переклад українською), єдиний суттєвий недолік цього рішення — коли програміст припускається помилки, то, інколи, асемблер не повідомляє про неї, а просто не засемблює ту мнемоніку, яка містить помилку (в майбутньому виправлю). Для додавання підримки архітектури CHIP-8 необхідно підключити заголовковий файл "chip8-arch.inc".

Моя перша демка:

В демі дракон просто махає крилами на тлі нерухомого тексту, для виводу якого уживалися як спрайтові команди, так і вбудований в CHIP-8 шрифт для шістнадцяткових чисел. Стиль кодингу демки нарочито індуський, аби початківцям було леше розібратися. Головною метою демки було знежучити заголовковий файл архітектури і показати наочно як легко додавати підтримку нової архітектури в FASM.

Один кадр демки:
https://replace.org.ua/extensions/om_images/img/5a04dd6917dcd/xjIGkV5.jpg

Один кадр з демки в середовищі знежучення

https://replace.org.ua/extensions/om_images/img/5a04dd6917dcd/rv9uYK6.jpg

В якості емуляторіа та знежучувача я послуговувався писаним мовою Go "CHIP-8, COPYRIGHT 2017 BY JEFFREY MASSUNG"

chip8-arch.inc (Файл, який відповідає за підтримку FASM`ом архітектури CHIP-8)
; This file adding support CHIP-8 architecture in FASM
; Written especially for replace.org.ua ukrainian coder forum
; (c) 0xDADA11C7, 2017

V0 equ 0xFFFF0
V1 equ 0xFFFF1
V2 equ 0xFFFF2
V3 equ 0xFFFF3
V4 equ 0xFFFF4
V5 equ 0xFFFF5
V6 equ 0xFFFF6
V7 equ 0xFFFF7
V8 equ 0xFFFF8
V9 equ 0xFFFF9
VA equ 0xFFFFA
VB equ 0xFFFFB
VC equ 0xFFFFC
VD equ 0xFFFFD
VE equ 0xFFFFE
VF equ 0xFFFFF

v0 equ V0
v1 equ V1
v2 equ V2
v3 equ V3
v4 equ V4
v5 equ V5
v6 equ V6
v7 equ V7
v8 equ V8
v9 equ V9
va equ VA
vb equ VB
vc equ VC
vd equ VD
ve equ VE
vf equ VF

macro cls {
  db 0x00, 0xE0
}

macro ret {
  db 0x00, 0xEE
}

macro sys a {
  db ((a shr 0x8) and 0xf), (a and 0xff)
}

macro jp a1, a2{
  if a1 = v0
    db 0xB0+((a2 shr 0x8) and 0xf), a2 and 0xff
  else
    db 0x10+((a1 shr 0x8) and 0xf), a1 and 0xff
  end if
}

macro call a {
  db 0x20+((a shr 0x8) and 0xf), (a and 0xff)
}

macro se vx, a {
  if ((vx >= v0) & (vx <= vf))
    if ((a >= v0) & (a <= vf))
      db 0x50+(vx and 0xF), (a and 0xF) shl 0x4
    else
      if ((a shr 8) = 0)
        db 0x30+(vx and 0xF), (a and 0xFF)
      else
        error 'Error: [se] invalid second (8-bit constant) argument'
      end if
    end if
  else
    error 'Error: [se] invalid first (vx register) argument'
  end if
}

macro sne vx, a {
  if ((vx >= v0) & (vx <= vf))
    if ((a >= v0) & (a <= vf))
      db 0x90+(vx and 0xF), (a and 0xF) shl 0x4
    else
      if ((a shr 8) = 0)
        db 0x40+(vx and 0xF), (a and 0xFF)
      else
        error 'Error: [sne] invalid second (8-bit constant) argument'
      end if
    end if
  else
    error 'Error: [sne] invalid first (vx register) argument'
  end if
}

macro ld a1, a2 {
  define ..defined 0
  match =dt, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x15
    else
    end if
    define ..defined 1
  \}
  match =DT, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x15
    else
    end if
    define ..defined 1
  \}
  match =dt, a2 \{
    if ((a1>=v0) & (a1<=vf))
      db (0xF0+(a1 and 0xF)), 0x7
    else
    end if
    define ..defined 1
  \}
  match =DT, a2 \{
    if ((a1>=v0) & (a1<=vf))
      db (0xF0+(a1 and 0xF)), 0x7
    else
    end if
    define ..defined 1
  \}
  match =st, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x18
    else
    end if
    define ..defined 1
  \}
  match =ST, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x18
    else
    end if
    define ..defined 1
  \}
  match =(=I=), a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x55
    end if
    define ..defined 1
  \}
  match =(=i=), a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x55
    end if
    define ..defined 1
  \}
  match =(=I=), a2 \{
    if ((a1>=v0) & (a1<=vf))
      db (0xF0+(a1 and 0xF)), 0x65
    end if
    define ..defined 1
  \}
  match =(=i=), a2 \{
    if ((a1>=v0) & (a1<=vf))
      db (0xF0+(a1 and 0xF)), 0x65
    end if
    define ..defined 1
  \}
  match =B, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x33
    end if
    define ..defined 1
  \}
  match =b, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x33
    end if
    define ..defined 1
  \}
  match =F, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x29
    end if
    define ..defined 1
  \}
  match =f, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x29
    end if
    define ..defined 1
  \}
;Fx0A - LD Vx, K 
  match =k, a2 \{
    if ((a1>=v0) & (a1<=vf))
      db (0xF0+(a1 and 0xF)), 0xA
    end if
    define ..defined 1
  \}
  match =K, a2 \{
    if ((a1>=v0) & (a1<=vf))
      db (0xF0+(a1 and 0xF)), 0xA
    end if
    define ..defined 1
  \}
  match =I, a1 \{
    db 0xA0+(a2 shr 0x8), (a2 and 0xFF)
    define ..defined 1
  \}
  if ..defined = 0
    if ((a1>=v0) & (a1<=vf)) 
      if ((a2>=v0) & (a2<=vf)))
        db (0x80+(a1 and 0xF)), ((a2 and 0xF) shl 0x4)
      else 
        db (0x60+(a1 and 0xF)), (a2 and 0xFF)
      end if
    end if
  end if
}

macro add a1, a2 {
  define ..defined 0
  match =I, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x1E
    end if
    define ..defined 1
  \}
  match =i, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db (0xF0+(a2 and 0xF)), 0x1E
    end if
    define ..defined 1
  \}
  if (..defined = 0) & ((a1>=v0) & (a1<=vf))
    if ((a2>=v0) & (a2<=vf))
      db 0x80+(a1 and 0xF), ((a2 and 0xF) shl 0x4)
    else
      db 0x70+(a1 and 0xF), (a2 and 0xff)
    end if
  end if 
}

macro or a1, a2 {
  if ((a2>=v0) & (a2<=vf)) & ((a1>=v0) & (a1<=vf))
    db 0x80+(a1 and 0xf), ((a2 and 0xf) shl 0x4)+0x1
  end if
}

macro and a1, a2 {
  if ((a2>=v0) & (a2<=vf)) & ((a1>=v0) & (a1<=vf))
    db 0x80+(a1 and 0xf), ((a2 and 0xf) shl 0x4)+0x2
  end if
}

macro xor vx, vy {
  if ((vx>=v0) & (vx<=vf)) & ((vy>=v0) & (vy<=vf))
    db 0x80+(vx and 0xf), ((vx and 0xf) shl 0x4)+0x3
  end if
}

macro add a1, a2 {
  define ..defined 0
  match =I, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db 0xF0+(a2 and 0xf), 0x1E
    end if
    define ..defined 1    
  \}
  match =i, a1 \{
    if ((a2>=v0) & (a2<=vf))
      db 0xF0+(a2 and 0xf), 0x1E
    end if
    define ..defined 1    
  \}
  if (..defined = 0) & (a1>=v0) & (a1<=vf) 
    if (a2>=v0) & (a2<=vf)
      db 0x80+(a1 and 0xf), ((a2 and 0xf) shl 0x4)+0x4
    else
      db 0x70+(a1 and 0xf), a2 and 0xff
    end if
  end if
}

macro sub vx, vy {
  if ((vx>=v0) & (vx<=vf) & (vy>=v0) & (vy<=vf))
    db 0x80+(vx and 0xf), ((vy and 0xf) shl 0x4)+0x5
    display 'hello'
  end if
}

macro subn a1, a2 {
  if ((a2>=v0) & (a2<=vf)) & ((a1>=v0) & (a1<=vf))
    db 0x80+(a1 and 0xf), ((a2 and 0xf) shl 0x4)+0x7
  end if
}

macro shr a1, a2 {
  if ((a1>=v0) & (a1<=vf))
     if a2 eq
       db 0x80+(a1 and 0xf), ((a1 and 0xf) shl 0x4)+0x6
     else 
       if (a2>=v0) & (a2<=vf)
         db 0x80+(a1 and 0xf), ((a2 and 0xf) shl 0x4)+0x6
       end if
     end if 
  end if
}

macro shl a1, a2 {
  if ((a1>=v0) & (a1<=vf))
     if a2 eq
       db 0x80+(a1 and 0xf), ((a1 and 0xf) shl 0x4)+0xE
     else 
       if (a2>=v0) & (a2<=vf)
         db 0x80+(a1 and 0xf), ((a2 and 0xf) shl 0x4)+0xE
       end if
     end if 
  end if
}

macro rnd a, b {
  if (a>=v0) & (a<=vf)
    db 0xC0+(a and 0xF), b and 0xFF
  end if
}

macro drw vx, vy, n {
  if (vx>=v0) & (vx<=vf) & (vy>=v0) & (vy<=vf) & (n <= 0xF) & (n >= 0)
    db 0xD0+(vx and 0xF), ((vy and 0xF) shl 0x4)+(n and 0xF)
  end if
}

macro skp vx {
  if ((vx>=v0) & (vx<=vf))
    db 0xE0+(vx and 0xf), 0x9E
  end if
}

macro sknp vx {
  if ((vx>=v0) & (vx<=vf))
    db 0xE0+(vx and 0xf), 0xA1
  end if
}
replace.asm (демо)
include 'chip8-arch.inc'

macro wait vx, hz {
  local ..up, ..down
    ld      vx, hz
    ld      DT, vx
..up:
    ld      vx, DT
    se      vx, 0x0
    jp      ..up
}

org 0x200
start:
    cls
    ld      V1, 0xF
    ld      V2, 0xA
    ld      V6, 0x9
    ld      I, msg.re
    drw     V2, V6, 0x5
    ld      I, line8
    drw     V2, V1, 0x1
    add     V2, 0x8
    ld      I, msg.pl
    drw     V2, V6, 0x5
    ld      I, line8
    drw     V2, V1, 0x1
    add     V2, 0x8
    ld      I, msg.ac
    drw     V2, V6, 0x5
    ld      I, line8
    drw     V2, V1, 0x1
    add     V2, 0x8
    ld      I, msg.e_dot
    drw     V2, V6, 0x5
    ld      I, line6
    drw     V2, V1, 0x1
    add     V2, 0x6
    ld      I, msg.or
    drw     V2, V6, 0x5
    ld      I, line8
    drw     V2, V1, 0x1
    add     V2, 0x8
    ld      I, msg.g_dot
    drw     V2, V6, 0x5
    ld      I, line6
    drw     V2, V1, 0x1
    add     V2, 0x7
    ld      I, msg.ua
    drw     V2, V6, 0x5
    ld      I, tail_end
    add     V2, -1
    drw     V2, V1, 0x6
    ld      V1, 0x9
    ld      V5, 0x1
    ld      V6, 0x9
    ld      I, dragon_body
    drw     V5, V6, 0x6
    ld      VA, V5
    ld      VB, V6
    add     VA, 0x8
    add     VB, 0x5
    ld      I, single_pixel
    drw     VA, VB, 0x1
    add     V6, -0x1
    add     V5, 0x4
    ld      V7, V5
;    add     V7, 0x1
    ld      V8, 0xA
    ld      V9, 0x12
    ld      I, msg_copyright.de
    drw     V8, V9, 0x4
    ld      I, msg_copyright.mo
    add     V8, 0x8
    drw     V8, V9, 0x4   
    add     V8, 0xB
    ld      I, msg_copyright.py
    drw     V8, V9, 0x4
    add     V8, 0x8
    ld      I, msg_copyright.sa
    drw     V8, V9, 0x4
    add     V8, 0x8
    ld      I, msg_copyright.ne
    drw     V8, V9, 0x4
    ld      V8, 0x2
    ld      V9, 0x17
    ld      VA, 0x0
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x5
    ld      I, msg_copyright.x
    drw     V8, V9, 0x5
    add     V8, 0x4
    ld      VA, 0xD
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x5
    ld      VA, 0xA
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x5
    ld      VA, 0xD
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x5
    ld      VA, 0xA
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x4
    ld      VA, 0x1
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x4
    ld      VA, 0x1
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x5
    ld      VA, 0xC
    ld      F, VA
    drw     V8, V9, 0x5
    add     V8, 0x5
    ld      VA, 0x7
    ld      F, VA
    drw     V8, V9, 0x5
    add     V9, 0x1
    add     V8, 0x5
    ld      I, msg_copyright.om1
    drw     V8, V9, 0x4
    add     V8, 0x8
    ld      I, msg_copyright.om2
    drw     V8, V9, 0x4
    add     V8, 0x8
wings:              
    ld      I, dragon_wings_1
    drw     V5, V6, 0x5
    wait    V1, 20
    drw     V5, V6, 0x5
    ld      I, dragon_wings_2
    drw     V7, V6, 0x5
    wait    V1, 20
    drw     V7, V6, 0x5
    ld      I, dragon_wings_3
    drw     V7, V6, 0x5
    wait    V1, 20
    drw     V7, V6, 0x5
    ld      I, dragon_wings_4
    drw     V7, V6, 0x5
    wait    V1, 20
    drw     V7, V6, 0x5
    ld      I, dragon_wings_3
    drw     V7, V6, 0x5
    wait    V1, 20
    drw     V7, V6, 0x5
    ld      I, dragon_wings_2
    drw     V7, V6, 0x5
    wait    V1, 20
    drw     V7, V6, 0x5
    jp      wings

dragon_body:
  db 0x40, 0xE0, 0x20, 0x3E, 0x1F, 0x0A
dragon_wings_1:
  db 0x38, 0x70, 0xE0, 0x80, 0x00
dragon_wings_2:
  db 0x00, 0x7C, 0xF8, 0xC0, 0x00
dragon_wings_3:
  db 0x00, 0x00, 0x7E, 0xF8, 0x00
dragon_wings_4:
  db 0x00, 0x00, 0x00, 0xFF, 0x1E
msg:
.re: 
  db 0xEE, 0xE8, 0xCE, 0xA8, 0xAE
.pl: 
  db 0xE8, 0xE8, 0x88, 0x88, 0x8E
.ac: 
  db 0xEE, 0xA8, 0xE8, 0xA8, 0xAE
.e_dot: 
  db 0xE0, 0x80, 0xE0, 0x80, 0xE8
.or:
  db 0xEE, 0xAE, 0xAC, 0xAA, 0xEA
.g_dot:
  db 0xF0, 0x80, 0xB0, 0x90, 0xF4
.ua:
  db 0xAE, 0xAA, 0xAE, 0xAA, 0x6A
tail_end:
  db 0xF0, 0x0C, 0x02, 0x22, 0x7C, 0x20

msg_copyright:
.de:
  db 0xCE, 0xEC, 0xE8, 0xCE
.mo:
  db 0xCE, 0xEA, 0xEA, 0xEE
.py:
  db 0xEA, 0xAA, 0xAA, 0xAC
.sa:
  db 0xE6, 0x8A, 0x8E, 0xEA
.ne:
  db 0xAE, 0xAC, 0xE8, 0xAE
.x:
  db 0xA0, 0xA0, 0x40, 0xA0, 0xA0
.om1:
  db 0xB9, 0xA9, 0x2A, 0x3A
.om2:
  db 0x40, 0x40, 0xA0, 0x20
single_pixel db 0x80
line8 db 0xff
line6 db 0xfc

До посту долучається архів з джерельними кодами демки і зкомпільованим бінарником replace.ch для запуску в емуляторі

Post's attachments

chip8.7z 2.24 kb, 364 downloads since 2017-11-09