mirror of
https://github.com/ares-emulator/ares.git
synced 2026-11-09 01:09:46 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1980fab09 | ||
|
|
ebb234ba5f | ||
|
|
2cc7fe30b4 | ||
|
|
5c3c872b78 | ||
|
|
36bf915244 | ||
|
|
045a0f7e79 | ||
|
|
a209e6ffbe | ||
|
|
3bf672dd97 | ||
|
|
157ddf3e8f | ||
|
|
ea23bf53ae | ||
|
|
d4598e1d01 | ||
|
|
f9a8564af0 | ||
|
|
6d66b1136d | ||
|
|
b01f18c34c | ||
|
|
1ebdb69516 | ||
|
|
add0f74387 | ||
|
|
b20f70f333 | ||
|
|
9aebf7bc6b | ||
|
|
a7bf219d5d | ||
|
|
04118be59a | ||
|
|
f24d17859f | ||
|
|
35fd80bde7 | ||
|
|
ccf1c00b58 | ||
|
|
f4520d41ec | ||
|
|
e308cf4275 | ||
|
|
192e53bb87 | ||
|
|
0ed9edfcdb | ||
|
|
764fe1974a | ||
|
|
a55d640459 | ||
|
|
6010bffe5d | ||
|
|
e492268025 | ||
|
|
a36c26c997 | ||
|
|
a3945e5772 | ||
|
|
6b6233b3af | ||
|
|
9f63cb1b99 | ||
|
|
49c39e0e4d | ||
|
|
7dec0b2a3c | ||
|
|
f288280ceb | ||
|
|
c6c5f4669c | ||
|
|
397b9c4505 | ||
|
|
7e2cfb6d40 | ||
|
|
970dcea0ac | ||
|
|
402c146a53 | ||
|
|
a471c150c9 | ||
|
|
ea38ea2537 | ||
|
|
09b326ae86 | ||
|
|
a60f667b25 | ||
|
|
6f7cf1bd31 | ||
|
|
8751bc433f | ||
|
|
afbee40bc0 | ||
|
|
81e9be64d2 | ||
|
|
0cd4972d11 | ||
|
|
938609818f | ||
|
|
487491e6f2 | ||
|
|
a6ccc7e5d2 | ||
|
|
39dd39cc09 | ||
|
|
1a017ff697 | ||
|
|
591adfcb25 |
No files matched your search
@@ -1,109 +0,0 @@
|
||||
#target := luna
|
||||
target := lucia
|
||||
build := performance
|
||||
openmp := false
|
||||
local := true
|
||||
flags += -I. -I..
|
||||
|
||||
$(info Targeting $(target) ...)
|
||||
|
||||
nall.path := ../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
ifeq ($(platform),local)
|
||||
flags += -march=native
|
||||
endif
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
options += -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||
options += -Wl,-enable-auto-import
|
||||
options += -Wl,-enable-runtime-pseudo-reloc
|
||||
else ifeq ($(platform),macos)
|
||||
else ifneq ($(filter $(platform),linux bsd),)
|
||||
options += -Wl,-export-dynamic
|
||||
options += -lX11 -lXext
|
||||
else
|
||||
$(error "unsupported platform")
|
||||
endif
|
||||
|
||||
objects := libco emulator
|
||||
|
||||
obj/libco.o: ../libco/libco.c
|
||||
obj/emulator.o: emulator/emulator.cpp
|
||||
|
||||
ifeq ($(target),luna)
|
||||
profile := accuracy
|
||||
cores := fc sfc sg ms md pce msx cv gb gba ws ngp
|
||||
endif
|
||||
|
||||
ifeq ($(target),lucia)
|
||||
profile := performance
|
||||
cores := fc sfc sg ms md pce msx gb gba ws ngp
|
||||
endif
|
||||
|
||||
ifeq ($(profile),accuracy)
|
||||
flags += -DPROFILE_ACCURACY
|
||||
endif
|
||||
|
||||
ifeq ($(profile),performance)
|
||||
flags += -DPROFILE_PERFORMANCE
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),fc),)
|
||||
include fc/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),sfc),)
|
||||
include sfc/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),sg),)
|
||||
include sg/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ms),)
|
||||
include ms/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),md),)
|
||||
include md/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),pce),)
|
||||
include pce/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),msx),)
|
||||
include msx/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),cv),)
|
||||
include cv/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),gb),)
|
||||
include gb/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),gba),)
|
||||
include gba/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ws),)
|
||||
include ws/GNUmakefile
|
||||
endif
|
||||
|
||||
ifneq ($(filter $(cores),ngp),)
|
||||
include ngp/GNUmakefile
|
||||
endif
|
||||
|
||||
include component/GNUmakefile
|
||||
|
||||
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
|
||||
ui := target-$(target)
|
||||
include $(ui)/GNUmakefile
|
||||
-include obj/*.d
|
||||
|
||||
clean:
|
||||
$(call delete,obj/*)
|
||||
$(call delete,out/*)
|
||||
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Whitespace-only changes.
Whitespace-only changes.
@@ -1,122 +0,0 @@
|
||||
layout
|
||||
name: Japanese
|
||||
|
||||
//row 0
|
||||
key: 0 わ を
|
||||
key: 1 ! ぬ
|
||||
key: 2 " ふ
|
||||
key: 3 # あ ぁ
|
||||
key: 4 $ う ぅ
|
||||
key: 5 % え ぇ
|
||||
key: 6 & お ぉ
|
||||
key: 7 ’ や ゃ
|
||||
|
||||
//row 1
|
||||
key: 8 ( ゆ ゅ
|
||||
key: 9 ) よ ょ
|
||||
key: - = ほ
|
||||
key: ^ ~ へ
|
||||
key: ¥ | ー
|
||||
key: @ ‘ "
|
||||
key: [ { 。
|
||||
key: ; + れ
|
||||
|
||||
//row 2
|
||||
key: : * け
|
||||
key: ] } む
|
||||
key: , < ね `
|
||||
key: . > る 。
|
||||
key: / ? め .
|
||||
key: - ろ
|
||||
key: A ち
|
||||
key: B こ
|
||||
|
||||
//row 3
|
||||
key: C そ
|
||||
key: D し
|
||||
key: E い ぃ
|
||||
key: F は
|
||||
key: G き
|
||||
key: H く
|
||||
key: I に
|
||||
key: J ま
|
||||
|
||||
//row 4
|
||||
key: K の
|
||||
key: L り
|
||||
key: M も
|
||||
key: N み
|
||||
key: O ら
|
||||
key: P せ
|
||||
key: Q た
|
||||
key: R す
|
||||
|
||||
//row 5
|
||||
key: S と
|
||||
key: T か
|
||||
key: U な
|
||||
key: V ひ
|
||||
key: W て
|
||||
key: X さ
|
||||
key: Y ん
|
||||
key: Z つ っ
|
||||
|
||||
//row 6
|
||||
key: SHIFT
|
||||
key: CTRL
|
||||
key: GRAPH
|
||||
key: CAPS
|
||||
key: かな
|
||||
key: F1 F6
|
||||
key: F2 F7
|
||||
key: F3 F8
|
||||
|
||||
//row 7
|
||||
key: F4 F9
|
||||
key: F5 F10
|
||||
key: ESC
|
||||
key: TAB
|
||||
key: STOP
|
||||
key: BS
|
||||
key: SELECT
|
||||
key: RETURN
|
||||
|
||||
//row 8
|
||||
key: SPACE
|
||||
key: CLS/HOME
|
||||
key: INS
|
||||
key: DEL
|
||||
key: ←
|
||||
key: ↑
|
||||
key: ↓
|
||||
key: →
|
||||
|
||||
//row 9
|
||||
key: *
|
||||
key: +
|
||||
key: /
|
||||
key: 0
|
||||
key: 1
|
||||
key: 2
|
||||
key: 3
|
||||
key: 4
|
||||
|
||||
//row 10
|
||||
key: 5
|
||||
key: 6
|
||||
key: 7
|
||||
key: 8
|
||||
key: 9
|
||||
key: -
|
||||
key: ,
|
||||
key: .
|
||||
|
||||
//row 11
|
||||
key:
|
||||
key: 実行
|
||||
key:
|
||||
key: 取消
|
||||
key:
|
||||
key:
|
||||
key:
|
||||
key:
|
||||
Binary file not shown.
Whitespace-only changes.
@@ -1,122 +0,0 @@
|
||||
layout
|
||||
name: Japanese
|
||||
|
||||
//row 0
|
||||
key: 0 わ を
|
||||
key: 1 ! ぬ
|
||||
key: 2 " ふ
|
||||
key: 3 # あ ぁ
|
||||
key: 4 $ う ぅ
|
||||
key: 5 % え ぇ
|
||||
key: 6 & お ぉ
|
||||
key: 7 ’ や ゃ
|
||||
|
||||
//row 1
|
||||
key: 8 ( ゆ ゅ
|
||||
key: 9 ) よ ょ
|
||||
key: - = ほ
|
||||
key: ^ ~ へ
|
||||
key: ¥ | ー
|
||||
key: @ ‘ "
|
||||
key: [ { 。
|
||||
key: ; + れ
|
||||
|
||||
//row 2
|
||||
key: : * け
|
||||
key: ] } む
|
||||
key: , < ね `
|
||||
key: . > る 。
|
||||
key: / ? め .
|
||||
key: - ろ
|
||||
key: A ち
|
||||
key: B こ
|
||||
|
||||
//row 3
|
||||
key: C そ
|
||||
key: D し
|
||||
key: E い ぃ
|
||||
key: F は
|
||||
key: G き
|
||||
key: H く
|
||||
key: I に
|
||||
key: J ま
|
||||
|
||||
//row 4
|
||||
key: K の
|
||||
key: L り
|
||||
key: M も
|
||||
key: N み
|
||||
key: O ら
|
||||
key: P せ
|
||||
key: Q た
|
||||
key: R す
|
||||
|
||||
//row 5
|
||||
key: S と
|
||||
key: T か
|
||||
key: U な
|
||||
key: V ひ
|
||||
key: W て
|
||||
key: X さ
|
||||
key: Y ん
|
||||
key: Z つ っ
|
||||
|
||||
//row 6
|
||||
key: SHIFT
|
||||
key: CTRL
|
||||
key: GRAPH
|
||||
key: CAPS
|
||||
key: かな
|
||||
key: F1 F6
|
||||
key: F2 F7
|
||||
key: F3 F8
|
||||
|
||||
//row 7
|
||||
key: F4 F9
|
||||
key: F5 F10
|
||||
key: ESC
|
||||
key: TAB
|
||||
key: STOP
|
||||
key: BS
|
||||
key: SELECT
|
||||
key: RETURN
|
||||
|
||||
//row 8
|
||||
key: SPACE
|
||||
key: CLS/HOME
|
||||
key: INS
|
||||
key: DEL
|
||||
key: ←
|
||||
key: ↑
|
||||
key: ↓
|
||||
key: →
|
||||
|
||||
//row 9
|
||||
key: *
|
||||
key: +
|
||||
key: /
|
||||
key: 0
|
||||
key: 1
|
||||
key: 2
|
||||
key: 3
|
||||
key: 4
|
||||
|
||||
//row 10
|
||||
key: 5
|
||||
key: 6
|
||||
key: 7
|
||||
key: 8
|
||||
key: 9
|
||||
key: -
|
||||
key: ,
|
||||
key: .
|
||||
|
||||
//row 11
|
||||
key:
|
||||
key: 実行
|
||||
key:
|
||||
key: 取消
|
||||
key:
|
||||
key:
|
||||
key:
|
||||
key:
|
||||
Binary file not shown.
Binary file not shown.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Binary file not shown.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Binary file not shown.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -1,962 +0,0 @@
|
||||
database
|
||||
revision: 2020-01-21
|
||||
|
||||
//Boards (Production)
|
||||
|
||||
database
|
||||
revision: 2020-01-21
|
||||
|
||||
board: BANDAI-PT-923
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
slot type=SufamiTurbo
|
||||
rom
|
||||
map address=20-3f,a0-bf:8000-ffff mask=0x8000
|
||||
ram
|
||||
map address=60-6f,e0-ef:0000-ffff
|
||||
slot type=SufamiTurbo
|
||||
rom
|
||||
map address=40-5f,c0-df:0000-ffff mask=0x8000
|
||||
ram
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
|
||||
board: BSC-1A5B9P-01
|
||||
memory type=RAM content=Save
|
||||
map address=10-17:5000-5fff mask=0xf000
|
||||
processor identifier=MCC
|
||||
map address=00-0f:5000-5fff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
map address=20-3f,a0-bf:6000-7fff
|
||||
memory type=ROM content=Program
|
||||
memory type=RAM content=Download
|
||||
slot type=BSMemory
|
||||
|
||||
board: BSC-1A5M-02
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f:8000-ffff mask=0xe08000 base=0x000000
|
||||
map address=20-3f:8000-ffff mask=0xe08000 base=0x100000
|
||||
map address=80-9f:8000-ffff mask=0xe08000 base=0x200000
|
||||
map address=a0-bf:8000-ffff mask=0xe08000 base=0x100000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
slot type=BSMemory
|
||||
map address=c0-ef:0000-ffff
|
||||
|
||||
board: BSC-1A7M-(01,10)
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f:8000-ffff mask=0xe08000 base=0x000000
|
||||
map address=20-3f:8000-ffff mask=0xe08000 base=0x100000
|
||||
map address=80-9f:8000-ffff mask=0xe08000 base=0x200000
|
||||
map address=a0-bf:8000-ffff mask=0xe08000 base=0x100000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
slot type=BSMemory
|
||||
map address=c0-ef:0000-ffff
|
||||
|
||||
board: BSC-1J3M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
slot type=BSMemory
|
||||
map address=20-3f,a0-bf:8000-ffff
|
||||
map address=60-7d,e0-ff:0000-ffff
|
||||
|
||||
board: BSC-1J5M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
slot type=BSMemory
|
||||
map address=20-3f,a0-bf:8000-ffff
|
||||
map address=60-7d,e0-ff:0000-ffff
|
||||
|
||||
board: BSC-1L3B-01
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
slot type=BSMemory
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: BSC-1L5B-01
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
slot type=BSMemory
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: SGB-R-10
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
processor identifier=ICD revision=2
|
||||
map address=00-3f,80-bf:6000-67ff,7000-7fff
|
||||
memory type=ROM content=Boot architecture=SM83
|
||||
slot type=GameBoy
|
||||
|
||||
board: SHVC-1A0N-(01,02,10,20,30)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-1A1B-(04,05,06)
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
|
||||
board: SHVC-1A1M-(01,10,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-1A3B-(11,12,13)
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
|
||||
board: SHVC-1A3B-20
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-1A3M-(10,20,21,30)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-1A5B-(02,04)
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
|
||||
board: SHVC-1A5M-(01,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-1B0N-(02,03,10)
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
processor architecture=uPD7725
|
||||
map address=30-3f,b0-bf:8000-ffff mask=0x3fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: SHVC-1B5B-02
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
processor architecture=uPD7725
|
||||
map address=20-3f,a0-bf:8000-ffff mask=0x3fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: SHVC-1C0N
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=60-7d,e0-ff:0000-ffff
|
||||
|
||||
board: SHVC-1C0N5S-01
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=60-7d,e0-ff:0000-ffff
|
||||
|
||||
board: SHVC-1CA0N5S-01
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71,f0-f1:0000-ffff
|
||||
|
||||
board: SHVC-1CA0N6S-01
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71,f0-f1:0000-ffff
|
||||
|
||||
board: SHVC-1CA6B-01
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71,f0-f1:0000-ffff
|
||||
|
||||
board: SHVC-1CB0N7S-01
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff mask=0x8000
|
||||
map address=40-5f:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71:0000-ffff
|
||||
|
||||
board: SHVC-1CB5B-(01,20)
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff mask=0x8000
|
||||
map address=40-5f:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71:0000-ffff
|
||||
|
||||
board: SHVC-1CB7B-01
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff mask=0x8000
|
||||
map address=40-5f:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71:0000-ffff
|
||||
|
||||
board: SHVC-1DC0N-01
|
||||
processor architecture=HG51BS169
|
||||
map address=00-3f,80-bf:6c00-6fff,7c00-7fff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-77:0000-7fff
|
||||
memory type=ROM content=Data architecture=HG51BS169
|
||||
memory type=RAM content=Data architecture=HG51BS169
|
||||
map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000
|
||||
oscillator
|
||||
|
||||
board: SHVC-1DS0B-20
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
processor architecture=uPD96050
|
||||
map address=60-67,e0-e7:0000-3fff
|
||||
memory type=ROM content=Program architecture=uPD96050
|
||||
memory type=ROM content=Data architecture=uPD96050
|
||||
memory type=RAM content=Data architecture=uPD96050
|
||||
map address=68-6f,e8-ef:0000-7fff mask=0x8000
|
||||
oscillator
|
||||
|
||||
board: SHVC-1J0N-(01,10,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
|
||||
board: SHVC-1J1M-(11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-1J3B-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-1J3M-(01,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-1J5M-(01,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-1K0N-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
processor architecture=uPD7725
|
||||
map address=00-1f,80-9f:6000-7fff mask=0xfff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: SHVC-1K1B-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
processor architecture=uPD7725
|
||||
map address=00-1f,80-9f:6000-7fff mask=0xfff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: SHVC-1K1X-10
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
processor architecture=uPD7725
|
||||
map address=00-1f,80-9f:6000-7fff mask=0xfff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: SHVC-1L0N3S-01
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: SHVC-1L3B-(02,11)
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: SHVC-1L5B-(11,20)
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: SHVC-1N0N-(01,10)
|
||||
processor identifier=SDD1
|
||||
map address=00-3f,80-bf:4800-480f
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
|
||||
board: SHVC-2A0N-01#A
|
||||
memory type=ROM content=Program
|
||||
map address=00-2f,80-af:8000-ffff mask=0x8000
|
||||
map address=40-6f,c0-ef:0000-ffff mask=0x8000
|
||||
|
||||
board: SHVC-2A0N-(01,10,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-2A1M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-2A3B-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-2A3M-01#A
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-2A3M-(01,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-2A5M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-2B3B-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
processor architecture=uPD7725
|
||||
map address=60-6f,e0-ef:0000-7fff mask=0x3fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: SHVC-2DC0N-01
|
||||
processor architecture=HG51BS169
|
||||
map address=00-3f,80-bf:6c00-6fff,7c00-7fff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-77:0000-7fff
|
||||
memory type=ROM content=Data architecture=HG51BS169
|
||||
memory type=RAM content=Data architecture=HG51BS169
|
||||
map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000
|
||||
oscillator
|
||||
|
||||
board: SHVC-2E3M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
processor identifier=OBC1
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
map address=70-71,f0-f1:6000-7fff,e000-ffff mask=0xe000
|
||||
memory type=RAM content=Save
|
||||
|
||||
board: SHVC-2J0N-(01,10,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
|
||||
board: SHVC-2J3M-(01,11,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=10-1f,30-3f,90-9f,b0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-2J5M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=10-1f,30-3f,90-9f,b0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-3J0N-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-2f,80-af:8000-ffff
|
||||
map address=40-6f,c0-ef:0000-ffff
|
||||
|
||||
board: SHVC-BA0N-(01,10)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-BA1M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-BA3M-(01,10)
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-BJ0N-(01,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
|
||||
board: SHVC-BJ1M-(10,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-BJ3M-(10,20)
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-LDH3C-01
|
||||
processor identifier=SPC7110
|
||||
map address=00-3f,80-bf:4800-483f
|
||||
map address=50,58:0000-ffff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x800000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=ROM content=Program
|
||||
memory type=ROM content=Data
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
rtc manufacturer=Epson
|
||||
map address=00-3f,80-bf:4840-4842
|
||||
memory type=RTC content=Time manufacturer=Epson
|
||||
|
||||
board: SHVC-LJ3M-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff base=0x400000
|
||||
map address=40-7d:0000-ffff base=0x400000
|
||||
map address=80-bf:8000-ffff mask=0xc00000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=RAM content=Save
|
||||
map address=80-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SHVC-LN3B-01
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
map address=70-73:0000-ffff
|
||||
processor identifier=SDD1
|
||||
map address=00-3f,80-bf:4800-480f
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
|
||||
board: SHVC-SGB2-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
processor identifier=ICD revision=2
|
||||
map address=00-3f,80-bf:6000-67ff,7000-7fff
|
||||
memory type=ROM content=Boot architecture=SM83
|
||||
oscillator
|
||||
slot type=GameBoy
|
||||
|
||||
board: SHVC-YA0N-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: SHVC-YJ0N-01
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
|
||||
//Boards (Generic)
|
||||
|
||||
database
|
||||
revision: 2020-01-01
|
||||
|
||||
board: ARM-LOROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-6f,c0-ef:0000-7fff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
processor architecture=ARM6
|
||||
map address=00-3f,80-bf:3800-38ff
|
||||
memory type=ROM content=Program architecture=ARM6
|
||||
memory type=ROM content=Data architecture=ARM6
|
||||
memory type=RAM content=Data architecture=ARM6
|
||||
oscillator
|
||||
|
||||
board: BS-HIROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
slot type=BSMemory
|
||||
map address=20-3f,a0-bf:8000-ffff
|
||||
map address=60-7d,e0-ff:0000-ffff
|
||||
|
||||
board: BS-LOROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f:8000-ffff mask=0xe08000 base=0x000000
|
||||
map address=20-3f:8000-ffff mask=0xe08000 base=0x100000
|
||||
map address=80-9f:8000-ffff mask=0xe08000 base=0x200000
|
||||
map address=a0-bf:8000-ffff mask=0xe08000 base=0x100000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
slot type=BSMemory
|
||||
map address=c0-ef:0000-ffff
|
||||
|
||||
board: BS-MCC-RAM
|
||||
memory type=RAM content=Save
|
||||
map address=10-17:5000-5fff mask=0xf000
|
||||
processor identifier=MCC
|
||||
map address=00-0f:5000-5fff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
map address=20-3f,a0-bf:6000-7fff
|
||||
memory type=ROM content=Program
|
||||
memory type=RAM content=Download
|
||||
slot type=BSMemory
|
||||
|
||||
board: BS-SA1-RAM
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
slot type=BSMemory
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: EVENT-CC92
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
processor manufacturer=NEC architecture=uPD78214
|
||||
identifier: Campus Challenge '92
|
||||
map address=c0,e0:0000
|
||||
mcu
|
||||
map address=00-1f,80-9f:8000-ffff
|
||||
memory type=ROM content=Program
|
||||
memory type=ROM content=Level-1
|
||||
memory type=ROM content=Level-2
|
||||
memory type=ROM content=Level-3
|
||||
dip
|
||||
processor manufacturer=NEC architecture=uPD7725
|
||||
map address=20-3f,a0-bf:8000-ffff mask=0x7fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: EVENT-PF94
|
||||
memory type=RAM content=Save
|
||||
map address=30-3f,b0-bf:6000-7fff mask=0xe000
|
||||
processor manufacturer=NEC architecture=uPD78214
|
||||
identifier: PowerFest '94
|
||||
map address=10,20:6000
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
memory type=ROM content=Level-1
|
||||
memory type=ROM content=Level-2
|
||||
memory type=ROM content=Level-3
|
||||
dip
|
||||
processor manufacturer=NEC architecture=uPD7725
|
||||
map address=00-0f,80-8f:6000-7fff mask=0xfff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: EXHIROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff base=0x400000
|
||||
map address=40-7d:0000-ffff base=0x400000
|
||||
map address=80-bf:8000-ffff mask=0xc00000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
|
||||
board: EXHIROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff base=0x400000
|
||||
map address=40-7d:0000-ffff base=0x400000
|
||||
map address=80-bf:8000-ffff mask=0xc00000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
map address=70-7d:0000-7fff
|
||||
|
||||
board: EXHIROM-RAM-SHARPRTC
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f:8000-ffff base=0x400000
|
||||
map address=40-7d:0000-ffff base=0x400000
|
||||
map address=80-bf:8000-ffff mask=0xc00000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
map address=70-7d:0000-7fff
|
||||
rtc manufacturer=Sharp
|
||||
map address=00-3f,80-bf:2800-2801
|
||||
memory type=RTC content=Time manufacturer=Sharp
|
||||
|
||||
board: EXLOROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d:8000-ffff mask=0x808000 base=0x400000
|
||||
map address=80-ff:8000-ffff mask=0x808000 base=0x000000
|
||||
|
||||
board: EXLOROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d:8000-ffff mask=0x808000 base=0x400000
|
||||
map address=80-ff:8000-ffff mask=0x808000 base=0x000000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: EXNEC-LOROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
processor architecture=uPD96050
|
||||
map address=60-67,e0-e7:0000-3fff
|
||||
memory type=ROM content=Program architecture=uPD96050
|
||||
memory type=ROM content=Data architecture=uPD96050
|
||||
memory type=RAM content=Data architecture=uPD96050
|
||||
map address=68-6f,e8-ef:0000-7fff mask=0x8000
|
||||
oscillator
|
||||
|
||||
board: EXSPC7110-RAM-EPSONRTC
|
||||
memory type=ROM content=Expansion
|
||||
map address=40-4f:0000-ffff
|
||||
processor identifier=SPC7110
|
||||
map address=00-3f,80-bf:4800-483f
|
||||
map address=50,58:0000-ffff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x800000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=ROM content=Program
|
||||
memory type=ROM content=Data
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
rtc manufacturer=Epson
|
||||
map address=00-3f,80-bf:4840-4842
|
||||
memory type=RTC content=Time manufacturer=Epson
|
||||
|
||||
board: GB-LOROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
processor identifier=ICD revision=2
|
||||
map address=00-3f,80-bf:6000-67ff,7000-7fff
|
||||
memory type=ROM content=Boot architecture=SM83
|
||||
oscillator
|
||||
slot type=GameBoy
|
||||
|
||||
board: GSU-RAM
|
||||
processor architecture=GSU
|
||||
map address=00-3f,80-bf:3000-34ff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
map address=40-5f,c0-df:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=70-71,f0-f1:0000-ffff
|
||||
|
||||
board: HIROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
|
||||
board: HIROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: HITACHI-LOROM
|
||||
processor architecture=HG51BS169
|
||||
map address=00-3f,80-bf:6c00-6fff,7c00-7fff
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-77:0000-7fff
|
||||
memory type=ROM content=Data architecture=HG51BS169
|
||||
memory type=RAM content=Data architecture=HG51BS169
|
||||
map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000
|
||||
oscillator
|
||||
|
||||
board: LOROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
|
||||
board: LOROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-7d,80-ff:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
|
||||
board: LOROM-RAM#A
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff mask=0x8000
|
||||
|
||||
board: NEC-HIROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
processor architecture=uPD7725
|
||||
map address=00-1f,80-9f:6000-7fff mask=0xfff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: NEC-HIROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=40-7d,c0-ff:0000-ffff
|
||||
memory type=RAM content=Save
|
||||
map address=20-3f,a0-bf:6000-7fff mask=0xe000
|
||||
processor architecture=uPD7725
|
||||
map address=00-1f,80-9f:6000-7fff mask=0xfff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: NEC-LOROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
processor architecture=uPD7725
|
||||
map address=30-3f,b0-bf:8000-ffff mask=0x3fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: NEC-LOROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-7fff mask=0x8000
|
||||
processor architecture=uPD7725
|
||||
map address=60-6f,e0-ef:0000-7fff mask=0x3fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: NEC-LOROM-RAM#A
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
memory type=RAM content=Save
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
processor architecture=uPD7725
|
||||
map address=20-3f,a0-bf:8000-ffff mask=0x3fff
|
||||
memory type=ROM content=Program architecture=uPD7725
|
||||
memory type=ROM content=Data architecture=uPD7725
|
||||
memory type=RAM content=Data architecture=uPD7725
|
||||
oscillator
|
||||
|
||||
board: OBC1-LOROM-RAM
|
||||
memory type=ROM content=Program
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x8000
|
||||
processor identifier=OBC1
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
map address=70-71,f0-f1:6000-7fff,e000-ffff mask=0xe000
|
||||
memory type=RAM content=Save
|
||||
|
||||
board: SA1-RAM
|
||||
processor architecture=W65C816S
|
||||
map address=00-3f,80-bf:2200-23ff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x408000
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff size=0x2000
|
||||
map address=40-4f:0000-ffff
|
||||
memory type=RAM content=Internal
|
||||
map address=00-3f,80-bf:3000-37ff size=0x800
|
||||
|
||||
board: SDD1
|
||||
processor identifier=SDD1
|
||||
map address=00-3f,80-bf:4800-480f
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
|
||||
board: SDD1-RAM
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
map address=70-73:0000-ffff mask=0x8000
|
||||
processor identifier=SDD1
|
||||
map address=00-3f,80-bf:4800-480f
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff
|
||||
map address=c0-ff:0000-ffff
|
||||
memory type=ROM content=Program
|
||||
|
||||
board: SPC7110-RAM
|
||||
processor identifier=SPC7110
|
||||
map address=00-3f,80-bf:4800-483f
|
||||
map address=50,58:0000-ffff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x800000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=ROM content=Program
|
||||
memory type=ROM content=Data
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
|
||||
board: SPC7110-RAM-EPSONRTC
|
||||
processor identifier=SPC7110
|
||||
map address=00-3f,80-bf:4800-483f
|
||||
map address=50,58:0000-ffff
|
||||
mcu
|
||||
map address=00-3f,80-bf:8000-ffff mask=0x800000
|
||||
map address=c0-ff:0000-ffff mask=0xc00000
|
||||
memory type=ROM content=Program
|
||||
memory type=ROM content=Data
|
||||
memory type=RAM content=Save
|
||||
map address=00-3f,80-bf:6000-7fff mask=0xe000
|
||||
rtc manufacturer=Epson
|
||||
map address=00-3f,80-bf:4840-4842
|
||||
memory type=RTC content=Time manufacturer=Epson
|
||||
|
||||
board: ST-LOROM
|
||||
memory type=ROM content=Program
|
||||
map address=00-1f,80-9f:8000-ffff mask=0x8000
|
||||
slot type=SufamiTurbo
|
||||
rom
|
||||
map address=20-3f,a0-bf:8000-ffff mask=0x8000
|
||||
ram
|
||||
map address=60-6f,e0-ef:0000-ffff
|
||||
slot type=SufamiTurbo
|
||||
rom
|
||||
map address=40-5f,c0-df:0000-ffff mask=0x8000
|
||||
ram
|
||||
map address=70-7d,f0-ff:0000-ffff
|
||||
|
||||
Binary file not shown.
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,53 +0,0 @@
|
||||
components := $(call unique,$(components))
|
||||
|
||||
objects += $(if $(findstring ay38910,$(components)),audio-ay38910)
|
||||
objects += $(if $(findstring sn76489,$(components)),audio-sn76489)
|
||||
objects += $(if $(findstring t6w28,$(components)),audio-t6w28)
|
||||
objects += $(if $(findstring ym2149,$(components)),audio-ym2149)
|
||||
objects += $(if $(findstring ym2413,$(components)),audio-ym2413)
|
||||
|
||||
objects += $(if $(findstring m93lcx6,$(components)),eeprom-m93lcx6)
|
||||
objects += $(if $(findstring x24c01,$(components)),eeprom-x24c01)
|
||||
|
||||
objects += $(if $(findstring arm7tdmi,$(components)),processor-arm7tdmi)
|
||||
objects += $(if $(findstring gsu,$(components)),processor-gsu)
|
||||
objects += $(if $(findstring hg51b,$(components)),processor-hg51b)
|
||||
objects += $(if $(findstring huc6280,$(components)),processor-huc6280)
|
||||
objects += $(if $(findstring m68k,$(components)),processor-m68k)
|
||||
objects += $(if $(findstring mos6502,$(components)),processor-mos6502)
|
||||
objects += $(if $(findstring sm83,$(components)),processor-sm83)
|
||||
objects += $(if $(findstring spc700,$(components)),processor-spc700)
|
||||
objects += $(if $(findstring tlcs900h,$(components)),processor-tlcs900h)
|
||||
objects += $(if $(findstring upd96050,$(components)),processor-upd96050)
|
||||
objects += $(if $(findstring v30mz,$(components)),processor-v30mz)
|
||||
objects += $(if $(findstring wdc65816,$(components)),processor-wdc65816)
|
||||
objects += $(if $(findstring z80,$(components)),processor-z80)
|
||||
|
||||
objects += $(if $(findstring tms9918,$(components)),video-tms9918)
|
||||
objects += $(if $(findstring v9938,$(components)),video-v9938)
|
||||
|
||||
obj/audio-ay38910.o: component/audio/ay38910/ay38910.cpp
|
||||
obj/audio-sn76489.o: component/audio/sn76489/sn76489.cpp
|
||||
obj/audio-t6w28.o: component/audio/t6w28/t6w28.cpp
|
||||
obj/audio-ym2149.o: component/audio/ym2149/ym2149.cpp
|
||||
obj/audio-ym2413.o: component/audio/ym2413/ym2413.cpp
|
||||
|
||||
obj/eeprom-m93lcx6.o: component/eeprom/m93lcx6/m93lcx6.cpp
|
||||
obj/eeprom-x24c01.o: component/eeprom/x24c01/x24c01.cpp
|
||||
|
||||
obj/processor-arm7tdmi.o: component/processor/arm7tdmi/arm7tdmi.cpp
|
||||
obj/processor-gsu.o: component/processor/gsu/gsu.cpp
|
||||
obj/processor-hg51b.o: component/processor/hg51b/hg51b.cpp
|
||||
obj/processor-huc6280.o: component/processor/huc6280/huc6280.cpp
|
||||
obj/processor-m68k.o: component/processor/m68k/m68k.cpp
|
||||
obj/processor-mos6502.o: component/processor/mos6502/mos6502.cpp
|
||||
obj/processor-sm83.o: component/processor/sm83/sm83.cpp
|
||||
obj/processor-spc700.o: component/processor/spc700/spc700.cpp
|
||||
obj/processor-tlcs900h.o: component/processor/tlcs900h/tlcs900h.cpp
|
||||
obj/processor-upd96050.o: component/processor/upd96050/upd96050.cpp
|
||||
obj/processor-v30mz.o: component/processor/v30mz/v30mz.cpp
|
||||
obj/processor-wdc65816.o: component/processor/wdc65816/wdc65816.cpp
|
||||
obj/processor-z80.o: component/processor/z80/z80.cpp
|
||||
|
||||
obj/video-tms9918.o: component/video/tms9918/tms9918.cpp
|
||||
obj/video-v9938.o: component/video/v9938/v9938.cpp
|
||||
@@ -1,225 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "ay38910.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto AY38910::clock() -> array<uint4[3]> {
|
||||
toneA.clock();
|
||||
toneB.clock();
|
||||
toneC.clock();
|
||||
noise.clock();
|
||||
envelope.clock();
|
||||
|
||||
array<uint4[3]> output;
|
||||
if((toneA.output | channelA.tone) & (noise.output | channelA.noise)) {
|
||||
output[0] = channelA.envelope ? envelope.output : channelA.volume;
|
||||
}
|
||||
if((toneB.output | channelB.tone) & (noise.output | channelB.noise)) {
|
||||
output[1] = channelB.envelope ? envelope.output : channelB.volume;
|
||||
}
|
||||
if((toneC.output | channelC.tone) & (noise.output |channelC.noise)) {
|
||||
output[2] = channelC.envelope ? envelope.output : channelC.volume;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
auto AY38910::Tone::clock() -> void {
|
||||
if(++counter >= period) {
|
||||
counter = 0;
|
||||
output ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto AY38910::Noise::clock() -> void {
|
||||
if(++counter >= period) {
|
||||
counter = 0;
|
||||
if(flip ^= 1) {
|
||||
output = !lfsr.bit(0);
|
||||
lfsr = (lfsr.bit(0) ^ lfsr.bit(3)) << 16 | lfsr >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto AY38910::Envelope::clock() -> void {
|
||||
if(!holding && ++counter >= period) {
|
||||
counter = 0;
|
||||
if(!attacking) {
|
||||
if(output != 0) return (void)output--;
|
||||
} else {
|
||||
if(output != 15) return (void)output++;
|
||||
}
|
||||
|
||||
if(!repeat) {
|
||||
output = 0;
|
||||
holding = 1;
|
||||
} else if(hold) {
|
||||
if(alternate) output ^= 15;
|
||||
holding = 1;
|
||||
} else if(alternate) {
|
||||
attacking ^= 1;
|
||||
} else {
|
||||
output = !attacking ? 15 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto AY38910::read() -> uint8 {
|
||||
uint8 data;
|
||||
|
||||
switch(io.register) {
|
||||
case 0:
|
||||
data.bit(0,7) = toneA.period.bit(0, 7);
|
||||
break;
|
||||
case 1:
|
||||
data.bit(0,3) = toneA.period.bit(8,11);
|
||||
break;
|
||||
case 2:
|
||||
data.bit(0,7) = toneB.period.bit(0, 7);
|
||||
break;
|
||||
case 3:
|
||||
data.bit(0,3) = toneB.period.bit(8,11);
|
||||
break;
|
||||
case 4:
|
||||
data.bit(0,7) = toneC.period.bit(0, 7);
|
||||
break;
|
||||
case 5:
|
||||
data.bit(0,3) = toneC.period.bit(8,11);
|
||||
break;
|
||||
case 6:
|
||||
data.bit(0,4) = noise.period;
|
||||
break;
|
||||
case 7:
|
||||
data.bit(0) = channelA.tone;
|
||||
data.bit(1) = channelB.tone;
|
||||
data.bit(2) = channelC.tone;
|
||||
data.bit(3) = channelA.noise;
|
||||
data.bit(4) = channelB.noise;
|
||||
data.bit(5) = channelC.noise;
|
||||
data.bit(6) = portA.direction;
|
||||
data.bit(7) = portB.direction;
|
||||
break;
|
||||
case 8:
|
||||
data.bit(0,3) = channelA.volume;
|
||||
data.bit(4) = channelA.envelope;
|
||||
break;
|
||||
case 9:
|
||||
data.bit(0,3) = channelB.volume;
|
||||
data.bit(4) = channelB.envelope;
|
||||
break;
|
||||
case 10:
|
||||
data.bit(0,3) = channelC.volume;
|
||||
data.bit(4) = channelC.envelope;
|
||||
break;
|
||||
case 11:
|
||||
data.bit(0,7) = envelope.period.bit(0, 7);
|
||||
break;
|
||||
case 12:
|
||||
data.bit(0,7) = envelope.period.bit(8,15);
|
||||
break;
|
||||
case 13:
|
||||
data.bit(0) = envelope.hold;
|
||||
data.bit(1) = envelope.alternate;
|
||||
data.bit(2) = envelope.attack;
|
||||
data.bit(3) = envelope.repeat;
|
||||
break;
|
||||
case 14:
|
||||
data.bit(0,7) = readIO(0);
|
||||
break;
|
||||
case 15:
|
||||
data.bit(0,7) = readIO(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto AY38910::write(uint8 data) -> void {
|
||||
switch(io.register) {
|
||||
case 0:
|
||||
toneA.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 1:
|
||||
toneA.period.bit(8,11) = data.bit(0,3);
|
||||
break;
|
||||
case 2:
|
||||
toneB.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 3:
|
||||
toneB.period.bit(8,11) = data.bit(0,3);
|
||||
break;
|
||||
case 4:
|
||||
toneC.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 5:
|
||||
toneC.period.bit(8,11) = data.bit(0,3);
|
||||
break;
|
||||
case 6:
|
||||
noise.period = data.bit(0,4);
|
||||
break;
|
||||
case 7:
|
||||
channelA.tone = data.bit(0);
|
||||
channelB.tone = data.bit(1);
|
||||
channelC.tone = data.bit(2);
|
||||
channelA.noise = data.bit(3);
|
||||
channelB.noise = data.bit(4);
|
||||
channelC.noise = data.bit(5);
|
||||
portA.direction = data.bit(6);
|
||||
portB.direction = data.bit(7);
|
||||
break;
|
||||
case 8:
|
||||
channelA.volume = data.bit(0,3);
|
||||
channelA.envelope = data.bit(4);
|
||||
break;
|
||||
case 9:
|
||||
channelB.volume = data.bit(0,3);
|
||||
channelB.envelope = data.bit(4);
|
||||
break;
|
||||
case 10:
|
||||
channelC.volume = data.bit(0,3);
|
||||
channelC.envelope = data.bit(4);
|
||||
break;
|
||||
case 11:
|
||||
envelope.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 12:
|
||||
envelope.period.bit(8,15) = data.bit(0,7);
|
||||
break;
|
||||
case 13:
|
||||
envelope.hold = data.bit(0);
|
||||
envelope.alternate = data.bit(1);
|
||||
envelope.attack = data.bit(2);
|
||||
envelope.repeat = data.bit(3);
|
||||
envelope.holding = 0;
|
||||
envelope.attacking = envelope.attack;
|
||||
envelope.output = !envelope.attacking ? 15 : 0;
|
||||
break;
|
||||
case 14:
|
||||
writeIO(0, data);
|
||||
break;
|
||||
case 15:
|
||||
writeIO(1, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto AY38910::select(uint4 data) -> void {
|
||||
io.register = data;
|
||||
}
|
||||
|
||||
auto AY38910::power() -> void {
|
||||
toneA = {};
|
||||
toneB = {};
|
||||
toneC = {};
|
||||
noise = {};
|
||||
envelope = {};
|
||||
channelA = {};
|
||||
channelB = {};
|
||||
channelC = {};
|
||||
portA = {};
|
||||
portB = {};
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//General Instrument AY-3-8910
|
||||
|
||||
struct AY38910 {
|
||||
virtual auto readIO(uint1 port) -> uint8 { return 0xff; }
|
||||
virtual auto writeIO(uint1 port, uint8 data) -> void {}
|
||||
|
||||
//ay38910.cpp
|
||||
auto clock() -> array<uint4[3]>;
|
||||
auto read() -> uint8;
|
||||
auto write(uint8 data) -> void;
|
||||
auto select(uint4 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
protected:
|
||||
struct Tone {
|
||||
//ay38910.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
uint12 counter;
|
||||
uint12 period;
|
||||
uint1 output;
|
||||
};
|
||||
|
||||
struct Noise {
|
||||
//ay38910.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
uint5 counter;
|
||||
uint5 period;
|
||||
uint1 flip;
|
||||
uint17 lfsr = 1;
|
||||
uint1 output;
|
||||
};
|
||||
|
||||
struct Envelope {
|
||||
//ay38910.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
uint16 counter;
|
||||
uint16 period;
|
||||
uint1 holding;
|
||||
uint1 attacking;
|
||||
uint1 hold;
|
||||
uint1 alternate;
|
||||
uint1 attack;
|
||||
uint1 repeat; //continue
|
||||
uint4 output;
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
uint1 tone; //0 = enable, 1 = disable
|
||||
uint1 noise; //0 = enable, 1 = disable
|
||||
uint1 envelope; //0 = use fixed volume, 1 = use envelope phase
|
||||
uint4 volume;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
uint1 direction; //0 = input, 1 = output
|
||||
uint8 data;
|
||||
};
|
||||
|
||||
struct IO {
|
||||
uint4 register;
|
||||
};
|
||||
|
||||
Tone toneA;
|
||||
Tone toneB;
|
||||
Tone toneC;
|
||||
Noise noise;
|
||||
Envelope envelope;
|
||||
Channel channelA;
|
||||
Channel channelB;
|
||||
Channel channelC;
|
||||
Port portA;
|
||||
Port portB;
|
||||
IO io;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
auto AY38910::serialize(serializer& s) -> void {
|
||||
s.integer(toneA.counter);
|
||||
s.integer(toneA.period);
|
||||
s.integer(toneA.output);
|
||||
|
||||
s.integer(toneB.counter);
|
||||
s.integer(toneB.period);
|
||||
s.integer(toneB.output);
|
||||
|
||||
s.integer(toneC.counter);
|
||||
s.integer(toneC.period);
|
||||
s.integer(toneC.output);
|
||||
|
||||
s.integer(noise.counter);
|
||||
s.integer(noise.period);
|
||||
s.integer(noise.flip);
|
||||
s.integer(noise.lfsr);
|
||||
s.integer(noise.output);
|
||||
|
||||
s.integer(envelope.counter);
|
||||
s.integer(envelope.period);
|
||||
s.integer(envelope.holding);
|
||||
s.integer(envelope.attacking);
|
||||
s.integer(envelope.hold);
|
||||
s.integer(envelope.alternate);
|
||||
s.integer(envelope.attack);
|
||||
s.integer(envelope.repeat);
|
||||
s.integer(envelope.output);
|
||||
|
||||
s.integer(channelA.tone);
|
||||
s.integer(channelA.noise);
|
||||
s.integer(channelA.envelope);
|
||||
s.integer(channelA.volume);
|
||||
|
||||
s.integer(channelB.tone);
|
||||
s.integer(channelB.noise);
|
||||
s.integer(channelB.envelope);
|
||||
s.integer(channelB.volume);
|
||||
|
||||
s.integer(channelC.tone);
|
||||
s.integer(channelC.noise);
|
||||
s.integer(channelC.envelope);
|
||||
s.integer(channelC.volume);
|
||||
|
||||
s.integer(portA.direction);
|
||||
s.integer(portA.data);
|
||||
|
||||
s.integer(portB.direction);
|
||||
s.integer(portB.data);
|
||||
|
||||
s.integer(io.register);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
auto SN76489::serialize(serializer& s) -> void {
|
||||
tone0.serialize(s);
|
||||
tone1.serialize(s);
|
||||
tone2.serialize(s);
|
||||
noise.serialize(s);
|
||||
s.integer(io.register);
|
||||
}
|
||||
|
||||
auto SN76489::Tone::serialize(serializer& s) -> void {
|
||||
s.integer(volume);
|
||||
s.integer(counter);
|
||||
s.integer(pitch);
|
||||
s.integer(output);
|
||||
}
|
||||
|
||||
auto SN76489::Noise::serialize(serializer& s) -> void {
|
||||
s.integer(volume);
|
||||
s.integer(counter);
|
||||
s.integer(pitch);
|
||||
s.integer(enable);
|
||||
s.integer(rate);
|
||||
s.integer(lfsr);
|
||||
s.integer(flip);
|
||||
s.integer(output);
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "sn76489.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto SN76489::clock() -> array<uint4[4]> {
|
||||
tone0.clock();
|
||||
tone1.clock();
|
||||
tone2.clock();
|
||||
noise.clock();
|
||||
|
||||
array<uint4[4]> output{15, 15, 15, 15};
|
||||
if(tone0.output) output[0] = tone0.volume;
|
||||
if(tone1.output) output[1] = tone1.volume;
|
||||
if(tone2.output) output[2] = tone2.volume;
|
||||
if(noise.output) output[3] = noise.volume;
|
||||
return output;
|
||||
}
|
||||
|
||||
auto SN76489::Tone::clock() -> void {
|
||||
if(!counter--) {
|
||||
counter = pitch;
|
||||
output ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto SN76489::Noise::clock() -> void {
|
||||
if(!counter--) {
|
||||
counter = array<uint10[4]>{0x10, 0x20, 0x40, pitch}[rate];
|
||||
if(flip ^= 1) { //0->1 transition
|
||||
output = !lfsr.bit(0);
|
||||
lfsr = (lfsr.bit(0) ^ lfsr.bit(3) & enable) << 15 | lfsr >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto SN76489::write(uint8 data) -> void {
|
||||
if(data.bit(7)) io.register = data.bit(4,6);
|
||||
|
||||
if(io.register.bit(0)) switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.volume = data.bit(0,3); break;
|
||||
case 1: tone1.volume = data.bit(0,3); break;
|
||||
case 2: tone2.volume = data.bit(0,3); break;
|
||||
case 3: noise.volume = data.bit(0,3); break;
|
||||
}
|
||||
|
||||
else if(data.bit(7)) switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.pitch.bit(0,3) = data.bit(0,3); break;
|
||||
case 1: tone1.pitch.bit(0,3) = data.bit(0,3); break;
|
||||
case 2: tone2.pitch.bit(0,3) = data.bit(0,3); noise.pitch = tone2.pitch; break;
|
||||
case 3: noise.rate = data.bit(0,1);
|
||||
noise.enable = data.bit(2);
|
||||
noise.lfsr = 0x8000;
|
||||
break;
|
||||
}
|
||||
|
||||
else switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
case 1: tone1.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
case 2: tone2.pitch.bit(4,9) = data.bit(0,5); noise.pitch = tone2.pitch; break;
|
||||
case 3: noise.volume = data.bit(0,3); break;
|
||||
}
|
||||
}
|
||||
|
||||
auto SN76489::power() -> void {
|
||||
tone0 = {};
|
||||
tone1 = {};
|
||||
tone2 = {};
|
||||
noise = {};
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//Texas Instruments SN76489
|
||||
|
||||
struct SN76489 {
|
||||
//sn76489.cpp
|
||||
auto clock() -> array<uint4[4]>;
|
||||
auto write(uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
protected:
|
||||
struct Tone {
|
||||
//sn76489.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint4 volume = 15;
|
||||
uint10 counter;
|
||||
uint10 pitch;
|
||||
uint1 output;
|
||||
};
|
||||
|
||||
struct Noise {
|
||||
//sn76489.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint4 volume = 15;
|
||||
uint10 counter;
|
||||
uint10 pitch;
|
||||
uint1 enable;
|
||||
uint2 rate;
|
||||
uint16 lfsr = 0x8000;
|
||||
uint1 flip;
|
||||
uint1 output;
|
||||
};
|
||||
|
||||
struct IO {
|
||||
uint3 register;
|
||||
};
|
||||
|
||||
Tone tone0;
|
||||
Tone tone1;
|
||||
Tone tone2;
|
||||
Noise noise;
|
||||
IO io;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
auto T6W28::serialize(serializer& s) -> void {
|
||||
tone0.serialize(s);
|
||||
tone1.serialize(s);
|
||||
tone2.serialize(s);
|
||||
noise.serialize(s);
|
||||
s.integer(io.register);
|
||||
}
|
||||
|
||||
auto T6W28::Tone::serialize(serializer& s) -> void {
|
||||
s.integer(counter);
|
||||
s.integer(pitch);
|
||||
s.integer(output);
|
||||
s.integer(volume.left);
|
||||
s.integer(volume.right);
|
||||
}
|
||||
|
||||
auto T6W28::Noise::serialize(serializer& s) -> void {
|
||||
s.integer(counter);
|
||||
s.integer(pitch);
|
||||
s.integer(enable);
|
||||
s.integer(rate);
|
||||
s.integer(lfsr);
|
||||
s.integer(flip);
|
||||
s.integer(output);
|
||||
s.integer(volume.left);
|
||||
s.integer(volume.right);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "t6w28.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto T6W28::clock() -> array<uint4[8]> {
|
||||
tone0.clock();
|
||||
tone1.clock();
|
||||
tone2.clock();
|
||||
noise.clock();
|
||||
|
||||
array<uint4[8]> output{15, 15, 15, 15, 15, 15, 15, 15};
|
||||
if(tone0.output) output[0] = tone0.volume.left, output[4] = tone0.volume.right;
|
||||
if(tone1.output) output[1] = tone1.volume.left, output[5] = tone1.volume.right;
|
||||
if(tone2.output) output[2] = tone2.volume.left, output[6] = tone2.volume.right;
|
||||
if(noise.output) output[3] = noise.volume.left, output[7] = noise.volume.right;
|
||||
return output;
|
||||
}
|
||||
|
||||
auto T6W28::Tone::clock() -> void {
|
||||
if(!counter--) {
|
||||
counter = pitch;
|
||||
output ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto T6W28::Noise::clock() -> void {
|
||||
if(!counter--) {
|
||||
counter = array<uint10[4]>{0x10, 0x20, 0x40, pitch}[rate];
|
||||
if(flip ^= 1) {
|
||||
output = !lfsr.bit(0);
|
||||
lfsr = (lfsr.bit(0) ^ lfsr.bit(2) & enable) << 14 | lfsr >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto T6W28::writeLeft(uint8 data) -> void {
|
||||
if(data.bit(7)) io.register = data.bit(4,6);
|
||||
|
||||
if(io.register.bit(0)) switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.volume.left = data.bit(0,3); break;
|
||||
case 1: tone1.volume.left = data.bit(0,3); break;
|
||||
case 2: tone2.volume.left = data.bit(0,3); break;
|
||||
case 3: noise.volume.left = data.bit(0,3); break;
|
||||
}
|
||||
|
||||
else if(data.bit(7)) switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.pitch.bit(0,3) = data.bit(0,3); break;
|
||||
case 1: tone1.pitch.bit(0,3) = data.bit(0,3); break;
|
||||
case 2: tone2.pitch.bit(0,3) = data.bit(0,3); break;
|
||||
}
|
||||
|
||||
else switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
case 1: tone1.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
case 2: tone2.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
}
|
||||
}
|
||||
|
||||
auto T6W28::writeRight(uint8 data) -> void {
|
||||
if(data.bit(7)) io.register = data.bit(4,6);
|
||||
|
||||
if(io.register.bit(0)) switch(io.register.bit(1,2)) {
|
||||
case 0: tone0.volume.right = data.bit(0,3); break;
|
||||
case 1: tone1.volume.right = data.bit(0,3); break;
|
||||
case 2: tone2.volume.right = data.bit(0,3); break;
|
||||
case 3: noise.volume.right = data.bit(0,3); break;
|
||||
}
|
||||
|
||||
else if(data.bit(7)) switch(io.register.bit(1,2)) {
|
||||
case 2: noise.pitch.bit(0,3) = data.bit(0,3); break;
|
||||
case 3: noise.rate = data.bit(0,1);
|
||||
noise.enable = data.bit(2);
|
||||
noise.lfsr = 0x4000;
|
||||
break;
|
||||
}
|
||||
|
||||
else switch(io.register.bit(1,2)) {
|
||||
case 2: noise.pitch.bit(4,9) = data.bit(0,5); break;
|
||||
}
|
||||
}
|
||||
|
||||
auto T6W28::power() -> void {
|
||||
tone0 = {};
|
||||
tone1 = {};
|
||||
tone2 = {};
|
||||
noise = {};
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//T6W28 (SN76489 variant)
|
||||
|
||||
struct T6W28 {
|
||||
//t6w28.cpp
|
||||
auto clock() -> array<uint4[8]>;
|
||||
auto writeLeft(uint8 data) -> void;
|
||||
auto writeRight(uint8 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
protected:
|
||||
struct Tone {
|
||||
//t6w28.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint10 counter;
|
||||
uint10 pitch;
|
||||
uint1 output;
|
||||
struct Volume {
|
||||
uint4 left = 15;
|
||||
uint4 right = 15;
|
||||
} volume;
|
||||
};
|
||||
|
||||
struct Noise {
|
||||
//t6w28.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint10 counter;
|
||||
uint10 pitch;
|
||||
uint1 enable;
|
||||
uint2 rate;
|
||||
uint15 lfsr = 0x4000;
|
||||
uint1 flip;
|
||||
uint1 output;
|
||||
struct Volume {
|
||||
uint4 left = 15;
|
||||
uint4 right = 15;
|
||||
} volume;
|
||||
};
|
||||
|
||||
struct IO {
|
||||
uint3 register;
|
||||
};
|
||||
|
||||
Tone tone0;
|
||||
Tone tone1;
|
||||
Tone tone2;
|
||||
Noise noise;
|
||||
IO io;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
auto YM2149::serialize(serializer& s) -> void {
|
||||
s.integer(toneA.counter);
|
||||
s.integer(toneA.period);
|
||||
s.integer(toneA.unused);
|
||||
s.integer(toneA.output);
|
||||
|
||||
s.integer(toneB.counter);
|
||||
s.integer(toneB.period);
|
||||
s.integer(toneB.unused);
|
||||
s.integer(toneB.output);
|
||||
|
||||
s.integer(toneC.counter);
|
||||
s.integer(toneC.period);
|
||||
s.integer(toneC.unused);
|
||||
s.integer(toneC.output);
|
||||
|
||||
s.integer(noise.counter);
|
||||
s.integer(noise.period);
|
||||
s.integer(noise.unused);
|
||||
s.integer(noise.flip);
|
||||
s.integer(noise.lfsr);
|
||||
s.integer(noise.output);
|
||||
|
||||
s.integer(envelope.counter);
|
||||
s.integer(envelope.period);
|
||||
s.integer(envelope.holding);
|
||||
s.integer(envelope.attacking);
|
||||
s.integer(envelope.hold);
|
||||
s.integer(envelope.alternate);
|
||||
s.integer(envelope.attack);
|
||||
s.integer(envelope.repeat);
|
||||
s.integer(envelope.unused);
|
||||
s.integer(envelope.output);
|
||||
|
||||
s.integer(channelA.tone);
|
||||
s.integer(channelA.noise);
|
||||
s.integer(channelA.envelope);
|
||||
s.integer(channelA.volume);
|
||||
s.integer(channelA.unused);
|
||||
|
||||
s.integer(channelB.tone);
|
||||
s.integer(channelB.noise);
|
||||
s.integer(channelB.envelope);
|
||||
s.integer(channelB.volume);
|
||||
s.integer(channelB.unused);
|
||||
|
||||
s.integer(channelC.tone);
|
||||
s.integer(channelC.noise);
|
||||
s.integer(channelC.envelope);
|
||||
s.integer(channelC.volume);
|
||||
s.integer(channelC.unused);
|
||||
|
||||
s.integer(portA.direction);
|
||||
s.integer(portA.data);
|
||||
|
||||
s.integer(portB.direction);
|
||||
s.integer(portB.data);
|
||||
|
||||
s.integer(io.register);
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "ym2149.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto YM2149::clock() -> array<uint5[3]> {
|
||||
toneA.clock();
|
||||
toneB.clock();
|
||||
toneC.clock();
|
||||
noise.clock();
|
||||
envelope.clock();
|
||||
|
||||
array<uint5[3]> output;
|
||||
if((toneA.output | channelA.tone) & (noise.output | channelA.noise)) {
|
||||
output[0] = channelA.envelope ? envelope.output : uint5(channelA.volume << 1 | 1);
|
||||
}
|
||||
if((toneB.output | channelB.tone) & (noise.output | channelB.noise)) {
|
||||
output[1] = channelB.envelope ? envelope.output : uint5(channelB.volume << 1 | 1);
|
||||
}
|
||||
if((toneC.output | channelC.tone) & (noise.output | channelC.noise)) {
|
||||
output[2] = channelC.envelope ? envelope.output : uint5(channelC.volume << 1 | 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
auto YM2149::Tone::clock() -> void {
|
||||
if(++counter >= period) {
|
||||
counter = 0;
|
||||
output ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2149::Noise::clock() -> void {
|
||||
if(++counter >= period) {
|
||||
counter = 0;
|
||||
if(flip ^= 1) {
|
||||
output = !lfsr.bit(0);
|
||||
lfsr = (lfsr.bit(0) ^ lfsr.bit(3)) << 16 | lfsr >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2149::Envelope::clock() -> void {
|
||||
if(holding) return;
|
||||
counter += 2;
|
||||
if(counter >= period) {
|
||||
counter = 0;
|
||||
if(!attacking) {
|
||||
if(output != 0) return (void)output--;
|
||||
} else {
|
||||
if(output != 31) return (void)output++;
|
||||
}
|
||||
|
||||
if(!repeat) {
|
||||
output = 0;
|
||||
holding = 1;
|
||||
} else if(hold) {
|
||||
if(alternate) output ^= 31;
|
||||
holding = 1;
|
||||
} else if(alternate) {
|
||||
attacking ^= 1;
|
||||
} else {
|
||||
output = !attacking ? 31 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2149::read() -> uint8 {
|
||||
uint8 data;
|
||||
|
||||
switch(io.register) {
|
||||
case 0:
|
||||
data.bit(0,7) = toneA.period.bit(0, 7);
|
||||
break;
|
||||
case 1:
|
||||
data.bit(0,3) = toneA.period.bit(8,11);
|
||||
data.bit(4,7) = toneA.unused.bit(0, 3);
|
||||
break;
|
||||
case 2:
|
||||
data.bit(0,7) = toneB.period.bit(0, 7);
|
||||
break;
|
||||
case 3:
|
||||
data.bit(0,3) = toneB.period.bit(8,11);
|
||||
data.bit(4,7) = toneB.unused.bit(0, 3);
|
||||
break;
|
||||
case 4:
|
||||
data.bit(0,7) = toneC.period.bit(0, 7);
|
||||
break;
|
||||
case 5:
|
||||
data.bit(0,3) = toneC.period.bit(8,11);
|
||||
data.bit(4,7) = toneC.unused.bit(0, 3);
|
||||
break;
|
||||
case 6:
|
||||
data.bit(0,4) = noise.period;
|
||||
data.bit(5,7) = noise.unused;
|
||||
break;
|
||||
case 7:
|
||||
data.bit(0) = channelA.tone;
|
||||
data.bit(1) = channelB.tone;
|
||||
data.bit(2) = channelC.tone;
|
||||
data.bit(3) = channelA.noise;
|
||||
data.bit(4) = channelB.noise;
|
||||
data.bit(5) = channelC.noise;
|
||||
data.bit(6) = portA.direction;
|
||||
data.bit(7) = portB.direction;
|
||||
break;
|
||||
case 8:
|
||||
data.bit(0,3) = channelA.volume;
|
||||
data.bit(4) = channelA.envelope;
|
||||
data.bit(5,7) = channelA.unused;
|
||||
break;
|
||||
case 9:
|
||||
data.bit(0,3) = channelB.volume;
|
||||
data.bit(4) = channelB.envelope;
|
||||
data.bit(5,7) = channelB.unused;
|
||||
break;
|
||||
case 10:
|
||||
data.bit(0,3) = channelC.volume;
|
||||
data.bit(4) = channelC.envelope;
|
||||
data.bit(5,7) = channelC.unused;
|
||||
break;
|
||||
case 11:
|
||||
data.bit(0,7) = envelope.period.bit(0, 7);
|
||||
break;
|
||||
case 12:
|
||||
data.bit(0,7) = envelope.period.bit(8,15);
|
||||
break;
|
||||
case 13:
|
||||
data.bit(0) = envelope.hold;
|
||||
data.bit(1) = envelope.alternate;
|
||||
data.bit(2) = envelope.attack;
|
||||
data.bit(3) = envelope.repeat;
|
||||
data.bit(4,7) = envelope.unused;
|
||||
break;
|
||||
case 14:
|
||||
data.bit(0,7) = portA.data;
|
||||
break;
|
||||
case 15:
|
||||
data.bit(0,7) = portB.data;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto YM2149::write(uint8 data) -> void {
|
||||
switch(io.register) {
|
||||
case 0:
|
||||
toneA.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 1:
|
||||
toneA.period.bit(8,11) = data.bit(0,3);
|
||||
toneA.unused.bit(0, 3) = data.bit(4,7);
|
||||
break;
|
||||
case 2:
|
||||
toneB.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 3:
|
||||
toneB.period.bit(8,11) = data.bit(0,3);
|
||||
toneB.unused.bit(0, 3) = data.bit(4,7);
|
||||
break;
|
||||
case 4:
|
||||
toneC.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 5:
|
||||
toneC.period.bit(8,11) = data.bit(0,3);
|
||||
toneC.unused.bit(0, 3) = data.bit(4,7);
|
||||
break;
|
||||
case 6:
|
||||
noise.period = data.bit(0,4);
|
||||
noise.unused = data.bit(5,7);
|
||||
break;
|
||||
case 7:
|
||||
channelA.tone = data.bit(0);
|
||||
channelB.tone = data.bit(1);
|
||||
channelC.tone = data.bit(2);
|
||||
channelA.noise = data.bit(3);
|
||||
channelB.noise = data.bit(4);
|
||||
channelC.noise = data.bit(5);
|
||||
portA.direction = data.bit(6);
|
||||
portB.direction = data.bit(7);
|
||||
break;
|
||||
case 8:
|
||||
channelA.volume = data.bit(0,3);
|
||||
channelA.envelope = data.bit(4);
|
||||
channelA.unused = data.bit(5,7);
|
||||
break;
|
||||
case 9:
|
||||
channelB.volume = data.bit(0,3);
|
||||
channelB.envelope = data.bit(4);
|
||||
channelB.unused = data.bit(5,7);
|
||||
break;
|
||||
case 10:
|
||||
channelC.volume = data.bit(0,3);
|
||||
channelC.envelope = data.bit(4);
|
||||
channelC.unused = data.bit(5,7);
|
||||
break;
|
||||
case 11:
|
||||
envelope.period.bit(0, 7) = data.bit(0,7);
|
||||
break;
|
||||
case 12:
|
||||
envelope.period.bit(8,15) = data.bit(0,7);
|
||||
break;
|
||||
case 13:
|
||||
envelope.hold = data.bit(0);
|
||||
envelope.alternate = data.bit(1);
|
||||
envelope.attack = data.bit(2);
|
||||
envelope.repeat = data.bit(3);
|
||||
envelope.unused = data.bit(4,7);
|
||||
envelope.holding = 0;
|
||||
envelope.attacking = envelope.attack;
|
||||
envelope.output = !envelope.attacking ? 31 : 0;
|
||||
break;
|
||||
case 14:
|
||||
portA.data = data;
|
||||
break;
|
||||
case 15:
|
||||
portB.data = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2149::select(uint4 data) -> void {
|
||||
io.register = data;
|
||||
}
|
||||
|
||||
auto YM2149::power() -> void {
|
||||
toneA = {};
|
||||
toneB = {};
|
||||
toneC = {};
|
||||
noise = {};
|
||||
envelope = {};
|
||||
channelA = {};
|
||||
channelB = {};
|
||||
channelC = {};
|
||||
portA = {};
|
||||
portB = {};
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//Yamaha YM2149 (General Instrument AY-3-8910 derivative)
|
||||
|
||||
struct YM2149 {
|
||||
//ym2149.cpp
|
||||
auto clock() -> array<uint5[3]>;
|
||||
auto read() -> uint8;
|
||||
auto write(uint8 data) -> void;
|
||||
auto select(uint4 data) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
protected:
|
||||
struct Tone {
|
||||
//ym2149.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
uint12 counter;
|
||||
uint12 period;
|
||||
uint4 unused;
|
||||
uint1 output;
|
||||
};
|
||||
|
||||
struct Noise {
|
||||
//ym2149.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
uint5 counter;
|
||||
uint5 period;
|
||||
uint3 unused;
|
||||
uint1 flip;
|
||||
uint17 lfsr = 1;
|
||||
uint1 output;
|
||||
};
|
||||
|
||||
struct Envelope {
|
||||
//ym2149.cpp
|
||||
auto clock() -> void;
|
||||
|
||||
uint16 counter;
|
||||
uint16 period;
|
||||
uint1 holding;
|
||||
uint1 attacking;
|
||||
uint1 hold;
|
||||
uint1 alternate;
|
||||
uint1 attack;
|
||||
uint1 repeat; //continue
|
||||
uint4 unused;
|
||||
uint5 output;
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
uint1 tone; //0 = enable, 1 = disable
|
||||
uint1 noise; //0 = enable, 1 = disable
|
||||
uint1 envelope; //0 = use fixed volume, 1 = use envelope volume
|
||||
uint4 volume;
|
||||
uint3 unused;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
uint1 direction; //0 = input, 1 = output
|
||||
uint8 data;
|
||||
};
|
||||
|
||||
struct IO {
|
||||
uint4 register;
|
||||
};
|
||||
|
||||
Tone toneA;
|
||||
Tone toneB;
|
||||
Tone toneC;
|
||||
Noise noise;
|
||||
Envelope envelope;
|
||||
Channel channelA;
|
||||
Channel channelB;
|
||||
Channel channelC;
|
||||
Port portA;
|
||||
Port portB;
|
||||
IO io;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
const int8 YM2413::levelScaling[16] = {
|
||||
//-6 dB/octave, -6 dB/8 units
|
||||
//input: fnumber.bits(5,8)
|
||||
0, 24, 32, 37, 40, 43, 45, 47, 48, 50, 51, 52, 53, 54, 55, 56,
|
||||
};
|
||||
|
||||
const uint64 YM2413::envelopeSteps[17][2] = {
|
||||
//{attack sequence, decay sequence },
|
||||
{0x0101010101010101, 0x0101010101010101}, // 4..44
|
||||
{0x0101110101011101, 0x0101110101011101}, // 5..45
|
||||
{0x0111011101110111, 0x0111011101110111}, // 6..46
|
||||
{0x0111111101111111, 0x0111111101111111}, // 7..47
|
||||
{0x1111111111111111, 0x0101010101010101}, //48
|
||||
{0x1121112111211121, 0x0101110101011101}, //49
|
||||
{0x1212121212121212, 0x0111011101110111}, //50
|
||||
{0x1222122212221222, 0x0111111101111111}, //51
|
||||
{0x2222222222222222, 0x0101010101010101}, //52
|
||||
{0x2242224222422242, 0x0101010111110101}, //53
|
||||
{0x2424242424242424, 0x0101111101011111}, //54
|
||||
{0x2444244424442444, 0x0101111111111111}, //55
|
||||
{0x4444444444444444, 0x1111111111111111}, //56
|
||||
{0x4484448444844484, 0x1111111122221111}, //57
|
||||
{0x4848484848484848, 0x1111222211112222}, //58
|
||||
{0x4888488848884888, 0x1111222222222222}, //59
|
||||
{0x0000000000000000, 0x2222222222222222}, //60+
|
||||
};
|
||||
|
||||
/* these are approximations and are not hardware accurate */
|
||||
|
||||
const uint8 YM2413::melodicTonesOPLL[15][8] = {
|
||||
{0x61, 0x61, 0x1e, 0x17, 0xf0, 0x78, 0x00, 0x17},
|
||||
{0x13, 0x41, 0x1e, 0x0d, 0xd7, 0xf7, 0x13, 0x13},
|
||||
{0x13, 0x01, 0x99, 0x04, 0xf2, 0xf4, 0x11, 0x23},
|
||||
{0x21, 0x61, 0x1b, 0x07, 0xaf, 0x64, 0x40, 0x27},
|
||||
{0x22, 0x21, 0x1e, 0x06, 0xf0, 0x75, 0x08, 0x18},
|
||||
{0x31, 0x22, 0x16, 0x05, 0x90, 0x71, 0x00, 0x13},
|
||||
{0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x10, 0x17},
|
||||
{0x23, 0x21, 0x2d, 0x16, 0xc0, 0x70, 0x07, 0x07},
|
||||
{0x61, 0x61, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17},
|
||||
{0x61, 0x61, 0x0c, 0x18, 0x85, 0xf0, 0x70, 0x07},
|
||||
{0x23, 0x01, 0x07, 0x11, 0xf0, 0xa4, 0x00, 0x22},
|
||||
{0x97, 0xc1, 0x24, 0x07, 0xff, 0xf8, 0x22, 0x12},
|
||||
{0x61, 0x10, 0x0c, 0x05, 0xf2, 0xf4, 0x40, 0x44},
|
||||
{0x01, 0x01, 0x55, 0x03, 0xf3, 0x92, 0xf3, 0xf3},
|
||||
{0x61, 0x41, 0x89, 0x03, 0xf1, 0xf4, 0xf0, 0x13},
|
||||
};
|
||||
|
||||
const uint8 YM2413::rhythmTonesOPLL[3][8] = {
|
||||
{0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d},
|
||||
{0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8},
|
||||
{0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55},
|
||||
};
|
||||
|
||||
/* these tables were extracted from the VRC7 debug mode: likely inaccurate for the YM2413 */
|
||||
|
||||
const uint8 YM2413::melodicTonesVRC7[15][8] = {
|
||||
{0x03, 0x21, 0x05, 0x06, 0xe8, 0x81, 0x42, 0x27}, //1: violin
|
||||
{0x13, 0x41, 0x14, 0x0d, 0xd8, 0xf6, 0x23, 0x12}, //2: guitar
|
||||
{0x11, 0x11, 0x08, 0x08, 0xfa, 0xb2, 0x20, 0x12}, //3: piano
|
||||
{0x31, 0x61, 0x0c, 0x07, 0xa8, 0x64, 0x61, 0x27}, //4: flute
|
||||
{0x32, 0x21, 0x1e, 0x06, 0xe1, 0x76, 0x01, 0x28}, //5: clarinet
|
||||
{0x02, 0x01, 0x06, 0x00, 0xa3, 0xe2, 0xf4, 0xf4}, //6: oboe
|
||||
{0x21, 0x61, 0x1d, 0x07, 0x82, 0x81, 0x11, 0x07}, //7: trumpet
|
||||
{0x23, 0x21, 0x22, 0x17, 0xa2, 0x72, 0x01, 0x17}, //8: organ
|
||||
{0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01}, //9: horn
|
||||
{0xb5, 0x01, 0x0f, 0x0f, 0xa8, 0xa5, 0x51, 0x02}, //a: synthesizer
|
||||
{0x17, 0xc1, 0x24, 0x07, 0xf8, 0xf8, 0x22, 0x12}, //b: harpischord
|
||||
{0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16}, //c: vibraphone
|
||||
{0x01, 0x02, 0xd3, 0x05, 0xc9, 0x95, 0x03, 0x02}, //d: synthesizer bass
|
||||
{0x61, 0x63, 0x0c, 0x00, 0x94, 0xc0, 0x33, 0xf6}, //e: acoustic bass
|
||||
{0x21, 0x72, 0x0d, 0x00, 0xc1, 0xd5, 0x56, 0x06}, //f: electric guitar
|
||||
};
|
||||
|
||||
const uint8 YM2413::rhythmTonesVRC7[3][8] = {
|
||||
{0x01, 0x01, 0x18, 0x0f, 0xdf, 0xf8, 0x6a, 0x6d}, //7, 13/16: bass drum
|
||||
{0x01, 0x01, 0x00, 0x00, 0xc8, 0xd8, 0xa7, 0x68}, //8, 14/17: hihat, snare drum
|
||||
{0x05, 0x01, 0x00, 0x00, 0xf8, 0xaa, 0x59, 0x55}, //9, 15/18: tomtom, top cymbal
|
||||
};
|
||||
|
||||
uint13 YM2413::sinTable[1 << 10];
|
||||
int12 YM2413::expTable[1 << 9];
|
||||
@@ -1,65 +0,0 @@
|
||||
auto YM2413::address(uint8 data) -> void {
|
||||
io.address = data;
|
||||
}
|
||||
|
||||
auto YM2413::write(uint8 data) -> void {
|
||||
uint4 index = io.address.bit(0,3) % 9;
|
||||
auto& voice = voices[index];
|
||||
|
||||
if(io.address >= 0x00 && io.address <= 0x07) {
|
||||
customTone[io.address] = data;
|
||||
for(uint n : range(9)) {
|
||||
if(voices[n].tone == 0) reload(n);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(io.address == 0x0e) {
|
||||
if(io.isVRC7) return;
|
||||
if(io.rhythmMode != data.bit(5)) {
|
||||
io.rhythmMode = data.bit(5);
|
||||
for(uint n : range(9)) reload(n);
|
||||
}
|
||||
if(io.rhythmMode) {
|
||||
hihat.trigger(data.bit(0));
|
||||
cymbal.trigger(data.bit(1));
|
||||
tomtom.trigger(data.bit(2));
|
||||
snare.trigger(data.bit(3));
|
||||
bass.carrier.trigger(data.bit(4));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(io.address == 0x0f) {
|
||||
//test register is currently unemulated
|
||||
return;
|
||||
}
|
||||
|
||||
if(io.address >= 0x10 && io.address <= 0x1f) { //0x19+ mirrors 0x10+
|
||||
if(io.isVRC7 && index >= 6) return;
|
||||
voice.fnumber.bit(0,7) = data;
|
||||
voice.update();
|
||||
return;
|
||||
}
|
||||
|
||||
if(io.address >= 0x20 && io.address <= 0x2f) { //0x29+ mirrors 0x20+
|
||||
if(io.isVRC7 && index >= 6) return;
|
||||
voice.fnumber.bit(8) = data.bit(0);
|
||||
voice.block = data.bit(1,3);
|
||||
uint1 keyOn = data.bit(4);
|
||||
uint1 sustainOn = data.bit(5);
|
||||
voice.update();
|
||||
voice.carrier.trigger(keyOn, sustainOn);
|
||||
return;
|
||||
}
|
||||
|
||||
if(io.address >= 0x30 && io.address <= 0x3f) { //0x39+ mirrors 0x30+
|
||||
if(io.isVRC7 && index >= 6) return;
|
||||
voice.level = data.bit(0,3);
|
||||
voice.tone = data.bit(4,7);
|
||||
if(io.rhythmMode && index >= 6) voice.update();
|
||||
else if(voice.tone) voice.update(melodicTones[voice.tone - 1]);
|
||||
else voice.update(customTone);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
auto YM2413::Operator::releaseRate() const -> uint4 {
|
||||
if(state == Trigger) return 13;
|
||||
if(state == Attack) return attack;
|
||||
if(state == Decay) return decay;
|
||||
if(state == Sustain) return sustainable ? (uint4)0 : release;
|
||||
// state == Release
|
||||
if(!audible) return 0; //should never happen
|
||||
if(sustainOn) return 5; //carrier only
|
||||
return sustainable ? release : (uint4)7;
|
||||
}
|
||||
|
||||
auto YM2413::Operator::update(maybe<uint> updateState) -> void {
|
||||
if(updateState) state = updateState();
|
||||
|
||||
auto baseRate = releaseRate();
|
||||
auto ksr = 2 * block + fnumber.bit(8) >> (scaleRate ? 0 : 2);
|
||||
|
||||
rate = min(60, baseRate ? 4 * baseRate + ksr : 0);
|
||||
divider = max(state == Attack ? 2 : 0, 13 - rate / 4);
|
||||
sequence = envelopeSteps[rate < 48 ? rate % 4 : rate - 44][state == Attack ? 0 : 1];
|
||||
|
||||
auto ksl = levelScaling[fnumber.bit(5,8)] + 8 * block - 56;
|
||||
level = totalLevel;
|
||||
level += max(0, scaleLevel ? ksl : 0) >> 3 - scaleLevel;
|
||||
auto f = fnumber.bit(6,8);
|
||||
long m = multiple;
|
||||
long lfo[8]{0, -f/2, -f, -f/2, 0, +f/2, +f, +f/2};
|
||||
|
||||
m += (m == 14) - (m == 13 || m == 11); //unimplemented; maps to 15, 12, or 10
|
||||
m = max(1, 2 * m); //0 => 1/2, which truncates fnumber bit 0
|
||||
|
||||
for(uint n : range(8)) {
|
||||
pitch[n] = (fnumber + lfo[n]) * m / 2 << block;
|
||||
}
|
||||
}
|
||||
|
||||
auto YM2413::Operator::synchronize(uint1 hard, maybe<Operator&> modulator) -> void {
|
||||
if(state == Trigger && envelope.bit(2,6) == 31) {
|
||||
update(Attack);
|
||||
if(rate >= 60) update(Decay), envelope = 0;
|
||||
if(hard) phase = 0;
|
||||
if(modulator) {
|
||||
modulator->update(Attack);
|
||||
if(modulator->rate >= 60) modulator->update(Decay), modulator->envelope = 0;
|
||||
if(hard) modulator->phase = 0;
|
||||
}
|
||||
}
|
||||
if(state == Attack && envelope == 0x00) update(Decay);
|
||||
if(state == Decay && envelope >= sustain << 3) update(Sustain);
|
||||
if(modulator) modulator->synchronize(hard);
|
||||
}
|
||||
|
||||
//only carriers (never modulators) call trigger()
|
||||
auto YM2413::Operator::trigger(uint1 key, uint1 sustain) -> void {
|
||||
sustainOn = sustain;
|
||||
if(keyOn == key) return;
|
||||
keyOn = key;
|
||||
update(keyOn ? Trigger : Release);
|
||||
}
|
||||
|
||||
auto YM2413::Operator::clock(natural clock, integer offset, integer modulation) -> int12 {
|
||||
uint14 y = YM2413::sinTable[uint10(offset + modulation)];
|
||||
if(waveform & ~y.bit(0)) y = sinTable[0];
|
||||
auto w = clock / 64 % 210 * tremolo;
|
||||
auto lfo = (w < 105 ? w : 210 - w) >> 3;
|
||||
y += envelope << 4 + 1;
|
||||
y += level << 5 + 1;
|
||||
y += lfo << 4 + 1;
|
||||
prior = output;
|
||||
output = expTable[y.bit(0,8)] * 1L >> y.bit(9,13);
|
||||
phase += pitch[clock / 1024 % 8 * vibrato];
|
||||
auto lsbs = divider ? clock.bit(0, divider - 1) : 0;
|
||||
if(rate && (state == Attack ? lsbs & -4 : lsbs) == 0) {
|
||||
natural msbs = uint4(clock >> divider);
|
||||
integer step = uint4(sequence << 4 * msbs >> 60);
|
||||
if(state == Attack) step = ~envelope * step >> 4;
|
||||
envelope = max(0x00, min(0x7f, envelope + step));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
auto YM2413::serialize(serializer& s) -> void {
|
||||
//melodicTones and rhythmTones are not serialized here:
|
||||
//they are reloaded during YM2413::power()
|
||||
s.array(customTone);
|
||||
for(auto& voice : voices) voice.serialize(s);
|
||||
s.integer(io.clock);
|
||||
s.integer(io.address);
|
||||
s.integer(io.rhythmMode);
|
||||
s.integer(io.noise);
|
||||
s.integer(io.isVRC7);
|
||||
}
|
||||
|
||||
auto YM2413::Voice::serialize(serializer& s) -> void {
|
||||
s.integer(tone);
|
||||
s.integer(fnumber);
|
||||
s.integer(block);
|
||||
s.integer(level);
|
||||
s.integer(feedback);
|
||||
modulator.serialize(s);
|
||||
carrier.serialize(s);
|
||||
}
|
||||
|
||||
auto YM2413::Operator::serialize(serializer& s) -> void {
|
||||
s.integer(slot);
|
||||
s.integer(keyOn);
|
||||
s.integer(sustainOn);
|
||||
s.integer(multiple);
|
||||
s.integer(scaleRate);
|
||||
s.integer(sustainable);
|
||||
s.integer(vibrato);
|
||||
s.integer(tremolo);
|
||||
s.integer(scaleLevel);
|
||||
s.integer(waveform);
|
||||
s.integer(attack);
|
||||
s.integer(decay);
|
||||
s.integer(sustain);
|
||||
s.integer(release);
|
||||
s.integer(totalLevel);
|
||||
s.integer(audible);
|
||||
|
||||
s.integer(state);
|
||||
s.integer(rate);
|
||||
s.integer(divider);
|
||||
s.integer(sequence);
|
||||
s.integer(envelope);
|
||||
s.integer(level);
|
||||
|
||||
s.integer(fnumber);
|
||||
s.integer(block);
|
||||
s.array(pitch);
|
||||
s.integer(phase);
|
||||
|
||||
s.integer(output);
|
||||
s.integer(prior);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
auto YM2413::Voice::update(const uint8* data) -> void {
|
||||
if(data) {
|
||||
modulator.multiple = data[0].bit(0,3);
|
||||
modulator.scaleRate = data[0].bit(4);
|
||||
modulator.sustainable = data[0].bit(5);
|
||||
modulator.vibrato = data[0].bit(6);
|
||||
modulator.tremolo = data[0].bit(7);
|
||||
|
||||
carrier.multiple = data[1].bit(0,3);
|
||||
carrier.scaleRate = data[1].bit(4);
|
||||
carrier.sustainable = data[1].bit(5);
|
||||
carrier.vibrato = data[1].bit(6);
|
||||
carrier.tremolo = data[1].bit(7);
|
||||
|
||||
modulator.totalLevel = data[2].bit(0,5);
|
||||
modulator.scaleLevel.bit(1) = data[2].bit(6);
|
||||
modulator.scaleLevel.bit(0) = data[2].bit(7); //bits swapped
|
||||
|
||||
feedback = data[3].bit(0,2);
|
||||
modulator.waveform = data[3].bit(3);
|
||||
carrier.waveform = data[3].bit(4);
|
||||
//unused = data[3].bit(5);
|
||||
carrier.scaleLevel.bit(1) = data[3].bit(6);
|
||||
carrier.scaleLevel.bit(0) = data[3].bit(7); //bits swapped
|
||||
|
||||
modulator.decay = data[4].bit(0,3);
|
||||
modulator.attack = data[4].bit(4,7);
|
||||
|
||||
carrier.decay = data[5].bit(0,3);
|
||||
carrier.attack = data[5].bit(4,7);
|
||||
|
||||
modulator.release = data[6].bit(0,3);
|
||||
modulator.sustain = data[6].bit(4,7);
|
||||
|
||||
carrier.release = data[7].bit(0,3);
|
||||
carrier.sustain = data[7].bit(4,7);
|
||||
}
|
||||
|
||||
modulator.block = block;
|
||||
modulator.fnumber = fnumber;
|
||||
if(modulator.audible) modulator.totalLevel = tone << 2;
|
||||
modulator.update();
|
||||
|
||||
carrier.block = block;
|
||||
carrier.fnumber = fnumber;
|
||||
carrier.totalLevel = level << 2;
|
||||
carrier.update();
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "ym2413.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "constants.cpp"
|
||||
#include "operator.cpp"
|
||||
#include "voice.cpp"
|
||||
#include "io.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto YM2413::clock() -> double {
|
||||
auto melody = 0;
|
||||
auto rhythm = 0;
|
||||
auto mask = -(1 << 12 - 9);
|
||||
|
||||
for(uint index : range(io.rhythmMode ? 6 : 9)) {
|
||||
auto& voice = voices[index];
|
||||
auto input = voice.modulator.output + voice.modulator.prior >> 8 - voice.feedback;
|
||||
voice.modulator.clock(io.clock, voice.modulator.phase >> 9, voice.feedback ? input : 0);
|
||||
voice.carrier.clock(io.clock, voice.carrier.phase >> 9, voice.modulator.output << 1);
|
||||
voice.carrier.synchronize(true, voice.modulator);
|
||||
melody += mask & voice.carrier.output;
|
||||
}
|
||||
|
||||
if(io.rhythmMode) {
|
||||
auto metallic = [](auto a, auto b) {
|
||||
return (a.bit(16) ^ a.bit(11)) | a.bit(12) | b.bit(14) | b.bit(12);
|
||||
};
|
||||
auto noise = io.noise.bit(0);
|
||||
auto m = metallic(hihat.phase, cymbal.phase);
|
||||
auto input = bass.modulator.output + bass.modulator.prior >> 8 - bass.feedback;
|
||||
bass.modulator.clock(io.clock, bass.modulator.phase >> 9, bass.feedback ? input : 0);
|
||||
bass.carrier.clock(io.clock, bass.carrier.phase >> 9, bass.modulator.output << 1);
|
||||
bass.carrier.synchronize(true, bass.modulator);
|
||||
rhythm += mask & bass.carrier.output;
|
||||
rhythm += mask & hihat.clock(io.clock, m << 9 | (m ^ noise ? 52 : 208));
|
||||
rhythm += mask & tomtom.clock(io.clock, tomtom.phase >> 9);
|
||||
rhythm += mask & snare.clock(io.clock, 1 << snare.phase.bit(17) + 8 ^ noise << 8);
|
||||
rhythm += mask & cymbal.clock(io.clock, m << 9 | 256);
|
||||
hihat.synchronize(false);
|
||||
snare.synchronize(true);
|
||||
tomtom.synchronize(true);
|
||||
cymbal.synchronize(false);
|
||||
}
|
||||
|
||||
auto mix = melody + 2 * rhythm;
|
||||
io.noise = io.noise >> 1 ^ io.noise.bit(0) * (1 << 22 | 1 << 8 | 1 << 7 | 1 << 0);
|
||||
if(++io.clock == 210 << 12) io.clock -= 210 << 12;
|
||||
return mix / 32768.0 * 4.0;
|
||||
}
|
||||
|
||||
auto YM2413::reload(uint4 index) -> void {
|
||||
auto& voice = voices[index];
|
||||
voice.modulator.audible = io.rhythmMode && index > 6;
|
||||
voice.carrier.audible = true;
|
||||
if(io.rhythmMode && index >= 6) voice.update(rhythmTones[index - 6]);
|
||||
else if(voice.tone) voice.update(melodicTones[voice.tone - 1]);
|
||||
else voice.update(customTone);
|
||||
}
|
||||
|
||||
auto YM2413::power(bool isVRC7) -> void {
|
||||
if(isVRC7) {
|
||||
memory::copy(melodicTones, sizeof(melodicTones), melodicTonesVRC7, sizeof(melodicTonesVRC7));
|
||||
memory::copy( rhythmTones, sizeof( rhythmTones), rhythmTonesVRC7, sizeof(rhythmTonesVRC7));
|
||||
} else {
|
||||
memory::copy(melodicTones, sizeof(melodicTones), melodicTonesOPLL, sizeof(melodicTonesOPLL));
|
||||
memory::copy( rhythmTones, sizeof( rhythmTones), rhythmTonesOPLL, sizeof(rhythmTonesOPLL));
|
||||
}
|
||||
for(auto& byte : customTone) byte = 0x00;
|
||||
|
||||
if(!sinTable[0] || !expTable[0])
|
||||
for(auto x : range(0x100)) {
|
||||
//10.9 fixed point phases
|
||||
auto y = sin((2 * x + 1) * Math::Pi / 1024.0); //0x400 units to 2pi radians
|
||||
auto z = -(1 << 8) * log(y) / log(2); //convert to -6 dB/256 units
|
||||
auto s = (1 << 10) * pow(2, uint8(~x) / 256.0); //0x7fa .. 0x400
|
||||
|
||||
sinTable[0x000 + x] = sinTable[0x1ff - x] = uint(z + 0.5) * 2 + 1;
|
||||
sinTable[0x200 + x] = sinTable[0x3ff - x] = uint(z + 0.5) * 2 + 0;
|
||||
|
||||
expTable[x * 2 + 1] = +uint(s + 0.5);
|
||||
expTable[x * 2 + 0] = ~uint(s + 0.5);
|
||||
}
|
||||
|
||||
io = {};
|
||||
io.isVRC7 = isVRC7;
|
||||
for(uint n : range(9)) {
|
||||
voices[n] = {};
|
||||
reload(n);
|
||||
}
|
||||
|
||||
for(uint n : range(3)) {
|
||||
voices[3 * n + 0].modulator.slot = 1 + 6 * n;
|
||||
voices[3 * n + 1].modulator.slot = 2 + 6 * n;
|
||||
voices[3 * n + 2].modulator.slot = 3 + 6 * n;
|
||||
voices[3 * n + 0].carrier.slot = 4 + 6 * n;
|
||||
voices[3 * n + 1].carrier.slot = 5 + 6 * n;
|
||||
voices[3 * n + 2].carrier.slot = 6 + 6 * n;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//Yamaha YM2413 (OPLL)
|
||||
//Author: Talarubi
|
||||
|
||||
struct YM2413 {
|
||||
//ym2413.cpp
|
||||
auto clock() -> double;
|
||||
auto reload(uint4 voice) -> void;
|
||||
auto power(bool isVRC7 = false) -> void;
|
||||
|
||||
//io.cpp
|
||||
auto address(uint8 data) -> void;
|
||||
auto write(uint8 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
protected:
|
||||
static const int8 levelScaling[16];
|
||||
static const uint64 envelopeSteps[17][2];
|
||||
static const uint8 melodicTonesOPLL[15][8];
|
||||
static const uint8 rhythmTonesOPLL[3][8];
|
||||
static const uint8 melodicTonesVRC7[15][8];
|
||||
static const uint8 rhythmTonesVRC7[3][8];
|
||||
static uint13 sinTable[1 << 10];
|
||||
static int12 expTable[1 << 9];
|
||||
uint8 melodicTones[15][8];
|
||||
uint8 rhythmTones[3][8];
|
||||
uint8 customTone[8];
|
||||
|
||||
enum : uint { Trigger, Attack, Decay, Sustain, Release };
|
||||
|
||||
struct Operator {
|
||||
//operator.cpp
|
||||
auto releaseRate() const -> uint4;
|
||||
auto update(maybe<uint> state = {}) -> void;
|
||||
auto synchronize(uint1 hard, maybe<Operator&> modulator = {}) -> void;
|
||||
auto trigger(uint1 key, uint1 sustain = 0) -> void;
|
||||
auto clock(natural clock, integer offset, integer modulation = 0) -> int12;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint5 slot; //1-18
|
||||
uint1 keyOn;
|
||||
uint1 sustainOn;
|
||||
uint4 multiple;
|
||||
uint1 scaleRate;
|
||||
uint1 sustainable;
|
||||
uint1 vibrato;
|
||||
uint1 tremolo;
|
||||
uint2 scaleLevel;
|
||||
uint1 waveform;
|
||||
uint4 attack;
|
||||
uint4 decay;
|
||||
uint4 sustain;
|
||||
uint4 release;
|
||||
uint6 totalLevel;
|
||||
uint1 audible;
|
||||
|
||||
//envelope generator
|
||||
uint3 state = Release;
|
||||
uint7 rate;
|
||||
uint4 divider;
|
||||
uint64 sequence;
|
||||
uint7 envelope = 0x7f;
|
||||
uint7 level;
|
||||
|
||||
//phase generator
|
||||
uint9 fnumber;
|
||||
uint3 block;
|
||||
uint19 pitch[8];
|
||||
uint19 phase;
|
||||
|
||||
//output
|
||||
int12 output;
|
||||
int12 prior;
|
||||
};
|
||||
|
||||
struct Voice {
|
||||
//voice.cpp
|
||||
auto update(const uint8* data = nullptr) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint4 tone;
|
||||
uint9 fnumber;
|
||||
uint3 block;
|
||||
uint4 level;
|
||||
uint3 feedback;
|
||||
|
||||
Operator modulator;
|
||||
Operator carrier;
|
||||
} voices[9];
|
||||
|
||||
struct IO {
|
||||
uint32 clock;
|
||||
uint8 address;
|
||||
uint1 rhythmMode;
|
||||
uint23 noise = 1;
|
||||
uint1 isVRC7 = 0;
|
||||
} io;
|
||||
|
||||
Voice& bass = voices[6];
|
||||
Operator& hihat = voices[7].modulator;
|
||||
Operator& snare = voices[7].carrier;
|
||||
Operator& tomtom = voices[8].modulator;
|
||||
Operator& cymbal = voices[8].carrier;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "m93lcx6.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
M93LCx6::operator bool() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
auto M93LCx6::reset() -> void {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
auto M93LCx6::allocate(uint size, uint width, uint8 fill) -> bool {
|
||||
if(size != 128 && size != 256 && size != 512 && size != 1024 && size != 2048) return false;
|
||||
if(width != 8 && width != 16) return false;
|
||||
|
||||
this->size = size;
|
||||
this->width = width;
|
||||
|
||||
for(auto& byte : data) byte = fill;
|
||||
|
||||
input.addressLength = 0;
|
||||
input.dataLength = width;
|
||||
|
||||
//note: the 93LC56 and 93LC76 have an extra dummy address bit
|
||||
if(size == 128) input.addressLength = width == 16 ? 6 : 7; //93LC46
|
||||
if(size == 256) input.addressLength = width == 16 ? 8 : 9; //93LC56
|
||||
if(size == 512) input.addressLength = width == 16 ? 8 : 9; //93LC66
|
||||
if(size == 1024) input.addressLength = width == 16 ? 10 : 11; //93LC76
|
||||
if(size == 2048) input.addressLength = width == 16 ? 10 : 11; //93LC86
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//used externally to program initial state values for uninitialized EEPROMs
|
||||
auto M93LCx6::program(uint11 address, uint8 value) -> void {
|
||||
data[address] = value;
|
||||
}
|
||||
|
||||
//1ms frequency
|
||||
auto M93LCx6::clock() -> void {
|
||||
//set during programming commands
|
||||
if(busy) busy--;
|
||||
}
|
||||
|
||||
auto M93LCx6::power() -> void {
|
||||
//writable = 0;
|
||||
busy = 0;
|
||||
|
||||
input.flush();
|
||||
output.flush();
|
||||
}
|
||||
|
||||
auto M93LCx6::edge() -> void {
|
||||
//wait for start
|
||||
if(!input.start()) return;
|
||||
uint start = *input.start();
|
||||
|
||||
//start bit must be set
|
||||
if(start != 1) return input.flush();
|
||||
|
||||
//wait for opcode
|
||||
if(!input.opcode()) return;
|
||||
uint opcode = *input.opcode();
|
||||
|
||||
//wait for address
|
||||
if(!input.address()) return;
|
||||
|
||||
if(opcode == 0b00) {
|
||||
auto mode = *input.mode();
|
||||
if(mode == 0b00) return writeDisable();
|
||||
if(mode == 0b01) return writeAll();
|
||||
if(mode == 0b10) return eraseAll();
|
||||
if(mode == 0b11) return writeEnable();
|
||||
}
|
||||
if(opcode == 0b01) return write();
|
||||
if(opcode == 0b10) return read();
|
||||
if(opcode == 0b11) return erase();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto M93LCx6::read() -> void {
|
||||
uint address = *input.address() << (width == 16) & size - 1;
|
||||
output.flush();
|
||||
for(uint4 index : range(width)) {
|
||||
output.write(data[address + index.bit(3)].bit(index.bit(0,2)));
|
||||
}
|
||||
output.write(0); //reads have an extra dummy data bit
|
||||
}
|
||||
|
||||
auto M93LCx6::write() -> void {
|
||||
if(!input.data()) return; //wait for data
|
||||
if(!writable) return input.flush();
|
||||
uint address = *input.address() << (width == 16) & size - 1;
|
||||
for(uint4 index : range(width)) {
|
||||
data[address + index.bit(3)].bit(index.bit(0,2)) = input.read();
|
||||
}
|
||||
busy = 4; //milliseconds
|
||||
return input.flush();
|
||||
}
|
||||
|
||||
auto M93LCx6::erase() -> void {
|
||||
if(!writable) return input.flush();
|
||||
uint address = *input.address() << (width == 16) & size - 1;
|
||||
for(uint4 index : range(width)) {
|
||||
data[address + index.bit(3)].bit(index.bit(0,2)) = 1;
|
||||
}
|
||||
busy = 4; //milliseconds
|
||||
return input.flush();
|
||||
}
|
||||
|
||||
auto M93LCx6::writeAll() -> void {
|
||||
if(!input.data()) return; //wait for data
|
||||
if(!writable) return input.flush();
|
||||
auto word = *input.data();
|
||||
for(uint address = 0; address < 512;) {
|
||||
data[address++] = uint8(word >> (width == 16 ? 8 : 0));
|
||||
data[address++] = uint8(word >> 0);
|
||||
}
|
||||
busy = 16; //milliseconds
|
||||
return input.flush();
|
||||
}
|
||||
|
||||
auto M93LCx6::eraseAll() -> void {
|
||||
if(!writable) return input.flush();
|
||||
for(auto& byte : data) byte = 0xff;
|
||||
busy = 8; //milliseconds
|
||||
return input.flush();
|
||||
}
|
||||
|
||||
auto M93LCx6::writeEnable() -> void {
|
||||
writable = true;
|
||||
return input.flush();
|
||||
}
|
||||
|
||||
auto M93LCx6::writeDisable() -> void {
|
||||
writable = false;
|
||||
return input.flush();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto M93LCx6::ShiftRegister::flush() -> void {
|
||||
value = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
auto M93LCx6::ShiftRegister::edge() -> uint1 {
|
||||
return value.bit(0);
|
||||
}
|
||||
|
||||
auto M93LCx6::ShiftRegister::read() -> uint1 {
|
||||
uint1 bit = value.bit(0);
|
||||
value >>= 1;
|
||||
count--;
|
||||
return bit;
|
||||
}
|
||||
|
||||
auto M93LCx6::ShiftRegister::write(uint1 bit) -> void {
|
||||
value <<= 1;
|
||||
value.bit(0) = bit;
|
||||
count++;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto M93LCx6::InputShiftRegister::start() -> maybe<uint1> {
|
||||
if(count < 1) return {};
|
||||
return {value >> count - 1 & 1};
|
||||
}
|
||||
|
||||
auto M93LCx6::InputShiftRegister::opcode() -> maybe<uint2> {
|
||||
if(count < 1 + 2) return {};
|
||||
return {value >> count - 3 & 3};
|
||||
}
|
||||
|
||||
auto M93LCx6::InputShiftRegister::mode() -> maybe<uint2> {
|
||||
if(count < 1 + 2 + addressLength) return {};
|
||||
return {value >> count - 5 & 3};
|
||||
}
|
||||
|
||||
auto M93LCx6::InputShiftRegister::address() -> maybe<uint11> {
|
||||
if(count < 1 + 2 + addressLength) return {};
|
||||
return {value >> count - (3 + addressLength) & (1 << addressLength) - 1};
|
||||
}
|
||||
|
||||
auto M93LCx6::InputShiftRegister::data() -> maybe<uint16> {
|
||||
if(count < 1 + 2 + addressLength + dataLength) return {};
|
||||
return {value >> count - (3 + addressLength + dataLength) & (1 << dataLength) - 1};
|
||||
}
|
||||
|
||||
auto M93LCx6::InputShiftRegister::increment() -> void {
|
||||
value.bit(0, addressLength - 1)++;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//Microchip 93LCx6
|
||||
// 93LC46 => 1024 cells => 128 x 8-bit or 64 x 16-bit
|
||||
// 93LC56 => 2048 cells => 256 x 8-bit or 128 x 16-bit
|
||||
// 93LC66 => 4096 cells => 512 x 8-bit or 256 x 16-bit
|
||||
// 93LC76 => 8192 cells => 1024 x 8-bit or 512 x 16-bit
|
||||
// 93LC86 => 16384 cells => 2048 x 8-bit or 1024 x 16-bit
|
||||
|
||||
struct M93LCx6 {
|
||||
//m93lcx6.cpp
|
||||
explicit operator bool() const;
|
||||
auto reset() -> void;
|
||||
auto allocate(uint size, uint width, uint8 fill = 0xff) -> bool;
|
||||
auto program(uint11 address, uint8 data) -> void;
|
||||
auto clock() -> void;
|
||||
auto power() -> void;
|
||||
auto edge() -> void;
|
||||
|
||||
//chip commands
|
||||
auto read() -> void;
|
||||
auto write() -> void;
|
||||
auto erase() -> void;
|
||||
auto writeAll() -> void;
|
||||
auto eraseAll() -> void;
|
||||
auto writeEnable() -> void;
|
||||
auto writeDisable() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//it is awkward no matter if data is uint1[bits], uint8[bytes], or uint16[words]
|
||||
uint8 data[2048]; //uint8 was chosen solely for easier serialization and saving
|
||||
uint size; //in bytes
|
||||
uint width; //8-bit (ORG=0) or 16-bit (ORG=1) configuration
|
||||
|
||||
boolean writable; //EWEN, EWDS
|
||||
uint busy; //busy cycles in milliseconds remaining for programming (write) operations to complete
|
||||
|
||||
struct ShiftRegister {
|
||||
auto flush() -> void;
|
||||
auto edge() -> uint1;
|
||||
auto read() -> uint1;
|
||||
auto write(uint1 data) -> void;
|
||||
|
||||
uint32 value;
|
||||
uint32 count;
|
||||
};
|
||||
|
||||
struct InputShiftRegister : ShiftRegister {
|
||||
auto start() -> maybe<uint1>;
|
||||
auto opcode() -> maybe<uint2>;
|
||||
auto mode() -> maybe<uint2>;
|
||||
auto address() -> maybe<uint11>;
|
||||
auto data() -> maybe<uint16>;
|
||||
auto increment() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint32 addressLength;
|
||||
uint32 dataLength;
|
||||
} input;
|
||||
|
||||
struct OutputShiftRegister : ShiftRegister {
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
} output;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
auto M93LCx6::serialize(serializer& s) -> void {
|
||||
s.array(data);
|
||||
s.integer(size);
|
||||
s.integer(width);
|
||||
s.boolean(writable);
|
||||
s.integer(busy);
|
||||
input.serialize(s);
|
||||
output.serialize(s);
|
||||
}
|
||||
|
||||
auto M93LCx6::InputShiftRegister::serialize(serializer& s) -> void {
|
||||
s.integer(value);
|
||||
s.integer(count);
|
||||
s.integer(addressLength);
|
||||
s.integer(dataLength);
|
||||
}
|
||||
|
||||
auto M93LCx6::OutputShiftRegister::serialize(serializer& s) -> void {
|
||||
s.integer(value);
|
||||
s.integer(count);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
auto X24C01::serialize(serializer& s) -> void {
|
||||
s.array(memory);
|
||||
s.integer(clock.lo);
|
||||
s.integer(clock.hi);
|
||||
s.integer(clock.fall);
|
||||
s.integer(clock.rise);
|
||||
s.integer(clock.line);
|
||||
s.integer(data.lo);
|
||||
s.integer(data.hi);
|
||||
s.integer(data.fall);
|
||||
s.integer(data.rise);
|
||||
s.integer(data.line);
|
||||
s.integer((uint&)mode);
|
||||
s.integer(counter);
|
||||
s.integer(address);
|
||||
s.integer(input);
|
||||
s.integer(output);
|
||||
s.integer(line);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "x24c01.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto X24C01::reset() -> void {
|
||||
clock = {};
|
||||
data = {};
|
||||
mode = Mode::Idle;
|
||||
counter = 0;
|
||||
address = 0;
|
||||
input = 0;
|
||||
output = 0;
|
||||
line = 1;
|
||||
}
|
||||
|
||||
auto X24C01::read() -> uint1 {
|
||||
return line;
|
||||
}
|
||||
|
||||
auto X24C01::write(uint1 scl, uint1 sda) -> void {
|
||||
clock.write(scl);
|
||||
data.write(sda);
|
||||
|
||||
if(clock.hi && data.fall) {
|
||||
line = 1;
|
||||
mode = Mode::Address;
|
||||
counter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(clock.hi && data.rise) {
|
||||
line = 1;
|
||||
mode = Mode::Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
if(clock.rise) {
|
||||
if(mode == Mode::Address && counter < 8) {
|
||||
address = data.line << 7 | address >> 1;
|
||||
counter++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::Read && counter < 8) {
|
||||
line = output & 1;
|
||||
output >>= 1;
|
||||
counter++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::Write && counter < 8) {
|
||||
input = data.line << 7 | input >> 1;
|
||||
counter++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::AddressAcknowledge) {
|
||||
line = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::ReadAcknowledge) {
|
||||
line = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::WriteAcknowledge) {
|
||||
line = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(clock.fall) {
|
||||
if(mode == Mode::Address && counter == 8) {
|
||||
line = 1;
|
||||
mode = Mode::AddressAcknowledge;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::Read && counter == 8) {
|
||||
mode = Mode::ReadAcknowledge;
|
||||
address.bit(1,7)++;
|
||||
counter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::Write && counter == 8) {
|
||||
memory[address & 0x7f] = input;
|
||||
mode = Mode::WriteAcknowledge;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::AddressAcknowledge) {
|
||||
mode = address & 0x80 ? Mode::Read : Mode::Write;
|
||||
output = memory[address & 0x7f];
|
||||
counter = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::ReadAcknowledge) {
|
||||
mode = Mode::Read;
|
||||
if(!data.line) mode = Mode::Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == Mode::WriteAcknowledge) {
|
||||
mode = Mode::Idle;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto X24C01::erase(uint8 fill) -> void {
|
||||
for(auto& byte : memory) byte = fill;
|
||||
}
|
||||
|
||||
auto X24C01::Line::write(uint1 data) -> void {
|
||||
lo = !line && !data;
|
||||
hi = line && data;
|
||||
fall = line && !data;
|
||||
rise = !line && data;
|
||||
line = data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
//X24C01 => 1024 cells => 128 x 8-bit
|
||||
|
||||
struct X24C01 {
|
||||
//x24c01.cpp
|
||||
auto reset() -> void;
|
||||
auto read() -> uint1;
|
||||
auto write(uint1 clock, uint1 data) -> void;
|
||||
auto erase(uint8 fill = 0xff) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 memory[128];
|
||||
|
||||
private:
|
||||
enum class Mode : uint {
|
||||
Idle,
|
||||
Address, AddressAcknowledge,
|
||||
Read, ReadAcknowledge,
|
||||
Write, WriteAcknowledge,
|
||||
};
|
||||
|
||||
struct Line {
|
||||
//x24c01.cpp
|
||||
auto write(uint1 data) -> void;
|
||||
|
||||
uint1 lo;
|
||||
uint1 hi;
|
||||
uint1 fall;
|
||||
uint1 rise;
|
||||
uint1 line;
|
||||
};
|
||||
|
||||
Line clock;
|
||||
Line data;
|
||||
Mode mode;
|
||||
uint8 counter;
|
||||
uint8 address;
|
||||
uint8 input;
|
||||
uint8 output;
|
||||
uint1 line;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
auto ARM7TDMI::ADD(uint32 source, uint32 modify, bool carry) -> uint32 {
|
||||
uint32 result = source + modify + carry;
|
||||
if(cpsr().t || opcode.bit(20)) {
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr().v = 1 << 31 & (overflow);
|
||||
cpsr().c = 1 << 31 & (overflow ^ source ^ modify ^ result);
|
||||
cpsr().z = result == 0;
|
||||
cpsr().n = result.bit(31);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::ASR(uint32 source, uint8 shift) -> uint32 {
|
||||
carry = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
carry = shift > 32 ? source & 1 << 31 : source & 1 << shift - 1;
|
||||
source = shift > 31 ? (int32)source >> 31 : (int32)source >> shift;
|
||||
return source;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::BIT(uint32 result) -> uint32 {
|
||||
if(cpsr().t || opcode.bit(20)) {
|
||||
cpsr().c = carry;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().n = result.bit(31);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::LSL(uint32 source, uint8 shift) -> uint32 {
|
||||
carry = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
carry = shift > 32 ? 0 : source & 1 << 32 - shift;
|
||||
source = shift > 31 ? 0 : source << shift;
|
||||
return source;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::LSR(uint32 source, uint8 shift) -> uint32 {
|
||||
carry = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
carry = shift > 32 ? 0 : source & 1 << shift - 1;
|
||||
source = shift > 31 ? 0 : source >> shift;
|
||||
return source;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::MUL(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32 {
|
||||
idle();
|
||||
if(multiplier >> 8 && multiplier >> 8 != 0xffffff) idle();
|
||||
if(multiplier >> 16 && multiplier >> 16 != 0xffff) idle();
|
||||
if(multiplier >> 24 && multiplier >> 24 != 0xff) idle();
|
||||
product += multiplicand * multiplier;
|
||||
if(cpsr().t || opcode.bit(20)) {
|
||||
cpsr().z = product == 0;
|
||||
cpsr().n = product.bit(31);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::ROR(uint32 source, uint8 shift) -> uint32 {
|
||||
carry = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
if(shift &= 31) source = source << 32 - shift | source >> shift;
|
||||
carry = source & 1 << 31;
|
||||
return source;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::RRX(uint32 source) -> uint32 {
|
||||
carry = source.bit(0);
|
||||
return cpsr().c << 31 | source >> 1;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::SUB(uint32 source, uint32 modify, bool carry) -> uint32 {
|
||||
return ADD(source, ~modify, carry);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::TST(uint4 mode) -> bool {
|
||||
switch(mode) {
|
||||
case 0: return cpsr().z == 1; //EQ (equal)
|
||||
case 1: return cpsr().z == 0; //NE (not equal)
|
||||
case 2: return cpsr().c == 1; //CS (carry set)
|
||||
case 3: return cpsr().c == 0; //CC (carry clear)
|
||||
case 4: return cpsr().n == 1; //MI (negative)
|
||||
case 5: return cpsr().n == 0; //PL (positive)
|
||||
case 6: return cpsr().v == 1; //VS (overflow)
|
||||
case 7: return cpsr().v == 0; //VC (no overflow)
|
||||
case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher)
|
||||
case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same)
|
||||
case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal)
|
||||
case 11: return cpsr().n != cpsr().v; //LT (signed less than)
|
||||
case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than)
|
||||
case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal)
|
||||
case 14: return true; //AL (always)
|
||||
case 15: return false; //NV (never)
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "arm7tdmi.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "algorithms.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
ARM7TDMI::ARM7TDMI() {
|
||||
armInitialize();
|
||||
thumbInitialize();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::power() -> void {
|
||||
processor = {};
|
||||
processor.r15.modify = [&] { pipeline.reload = true; };
|
||||
pipeline = {};
|
||||
carry = 0;
|
||||
irq = 0;
|
||||
cpsr().f = 1;
|
||||
exception(PSR::SVC, 0x00);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
//ARMv4 (ARM7TDMI)
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
struct ARM7TDMI {
|
||||
enum : uint {
|
||||
Nonsequential = 1 << 0, //N cycle
|
||||
Sequential = 1 << 1, //S cycle
|
||||
Prefetch = 1 << 2, //instruction fetch
|
||||
Byte = 1 << 3, // 8-bit access
|
||||
Half = 1 << 4, //16-bit access
|
||||
Word = 1 << 5, //32-bit access
|
||||
Load = 1 << 6, //load operation
|
||||
Store = 1 << 7, //store operation
|
||||
Signed = 1 << 8, //sign-extend
|
||||
};
|
||||
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
virtual auto sleep() -> void = 0;
|
||||
virtual auto get(uint mode, uint32 address) -> uint32 = 0;
|
||||
virtual auto set(uint mode, uint32 address, uint32 word) -> void = 0;
|
||||
|
||||
//arm7tdmi.cpp
|
||||
ARM7TDMI();
|
||||
auto power() -> void;
|
||||
|
||||
//registers.cpp
|
||||
struct GPR;
|
||||
struct PSR;
|
||||
inline auto r(uint4) -> GPR&;
|
||||
inline auto cpsr() -> PSR&;
|
||||
inline auto spsr() -> PSR&;
|
||||
inline auto privileged() const -> bool;
|
||||
inline auto exception() const -> bool;
|
||||
|
||||
//memory.cpp
|
||||
auto idle() -> void;
|
||||
auto read(uint mode, uint32 address) -> uint32;
|
||||
auto load(uint mode, uint32 address) -> uint32;
|
||||
auto write(uint mode, uint32 address, uint32 word) -> void;
|
||||
auto store(uint mode, uint32 address, uint32 word) -> void;
|
||||
|
||||
//algorithms.cpp
|
||||
auto ADD(uint32, uint32, bool) -> uint32;
|
||||
auto ASR(uint32, uint8) -> uint32;
|
||||
auto BIT(uint32) -> uint32;
|
||||
auto LSL(uint32, uint8) -> uint32;
|
||||
auto LSR(uint32, uint8) -> uint32;
|
||||
auto MUL(uint32, uint32, uint32) -> uint32;
|
||||
auto ROR(uint32, uint8) -> uint32;
|
||||
auto RRX(uint32) -> uint32;
|
||||
auto SUB(uint32, uint32, bool) -> uint32;
|
||||
auto TST(uint4) -> bool;
|
||||
|
||||
//instruction.cpp
|
||||
auto fetch() -> void;
|
||||
auto instruction() -> void;
|
||||
auto exception(uint mode, uint32 address) -> void;
|
||||
auto armInitialize() -> void;
|
||||
auto thumbInitialize() -> void;
|
||||
|
||||
//instructions-arm.cpp
|
||||
auto armALU(uint4 mode, uint4 target, uint4 source, uint32 data) -> void;
|
||||
auto armMoveToStatus(uint4 field, uint1 source, uint32 data) -> void;
|
||||
|
||||
auto armInstructionBranch(int24, uint1) -> void;
|
||||
auto armInstructionBranchExchangeRegister(uint4) -> void;
|
||||
auto armInstructionDataImmediate(uint8, uint4, uint4, uint4, uint1, uint4) -> void;
|
||||
auto armInstructionDataImmediateShift(uint4, uint2, uint5, uint4, uint4, uint1, uint4) -> void;
|
||||
auto armInstructionDataRegisterShift(uint4, uint2, uint4, uint4, uint4, uint1, uint4) -> void;
|
||||
auto armInstructionLoadImmediate(uint8, uint1, uint4, uint4, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionLoadRegister(uint4, uint1, uint4, uint4, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMemorySwap(uint4, uint4, uint4, uint1) -> void;
|
||||
auto armInstructionMoveHalfImmediate(uint8, uint4, uint4, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveHalfRegister(uint4, uint4, uint4, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveImmediateOffset(uint12, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveMultiple(uint16, uint4, uint1, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveRegisterOffset(uint4, uint2, uint5, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveToRegisterFromStatus(uint4, uint1) -> void;
|
||||
auto armInstructionMoveToStatusFromImmediate(uint8, uint4, uint4, uint1) -> void;
|
||||
auto armInstructionMoveToStatusFromRegister(uint4, uint4, uint1) -> void;
|
||||
auto armInstructionMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> void;
|
||||
auto armInstructionMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionSoftwareInterrupt(uint24 immediate) -> void;
|
||||
auto armInstructionUndefined() -> void;
|
||||
|
||||
//instructions-thumb.cpp
|
||||
auto thumbInstructionALU(uint3, uint3, uint4) -> void;
|
||||
auto thumbInstructionALUExtended(uint4, uint4, uint2) -> void;
|
||||
auto thumbInstructionAddRegister(uint8, uint3, uint1) -> void;
|
||||
auto thumbInstructionAdjustImmediate(uint3, uint3, uint3, uint1) -> void;
|
||||
auto thumbInstructionAdjustRegister(uint3, uint3, uint3, uint1) -> void;
|
||||
auto thumbInstructionAdjustStack(uint7, uint1) -> void;
|
||||
auto thumbInstructionBranchExchange(uint4) -> void;
|
||||
auto thumbInstructionBranchFarPrefix(int11) -> void;
|
||||
auto thumbInstructionBranchFarSuffix(uint11) -> void;
|
||||
auto thumbInstructionBranchNear(int11) -> void;
|
||||
auto thumbInstructionBranchTest(int8, uint4) -> void;
|
||||
auto thumbInstructionImmediate(uint8, uint3, uint2) -> void;
|
||||
auto thumbInstructionLoadLiteral(uint8, uint3) -> void;
|
||||
auto thumbInstructionMoveByteImmediate(uint3, uint3, uint5, uint1) -> void;
|
||||
auto thumbInstructionMoveHalfImmediate(uint3, uint3, uint5, uint1) -> void;
|
||||
auto thumbInstructionMoveMultiple(uint8, uint3, uint1) -> void;
|
||||
auto thumbInstructionMoveRegisterOffset(uint3, uint3, uint3, uint3) -> void;
|
||||
auto thumbInstructionMoveStack(uint8, uint3, uint1) -> void;
|
||||
auto thumbInstructionMoveWordImmediate(uint3, uint3, uint5, uint1) -> void;
|
||||
auto thumbInstructionShiftImmediate(uint3, uint3, uint5, uint2) -> void;
|
||||
auto thumbInstructionSoftwareInterrupt(uint8) -> void;
|
||||
auto thumbInstructionStackMultiple(uint8, uint1, uint1) -> void;
|
||||
auto thumbInstructionUndefined() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassembleInstruction(maybe<uint32> pc = {}, maybe<boolean> thumb = {}) -> string;
|
||||
auto disassembleContext() -> string;
|
||||
|
||||
struct GPR {
|
||||
inline operator uint32_t() const { return data; }
|
||||
inline auto operator=(const GPR& value) -> GPR& { return operator=(value.data); }
|
||||
|
||||
inline auto operator=(uint32 value) -> GPR& {
|
||||
data = value;
|
||||
if(modify) modify();
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32 data;
|
||||
function<auto () -> void> modify;
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
enum : uint {
|
||||
USR = 0x10, //user
|
||||
FIQ = 0x11, //fast interrupt
|
||||
IRQ = 0x12, //interrupt
|
||||
SVC = 0x13, //service
|
||||
ABT = 0x17, //abort
|
||||
UND = 0x1b, //undefined
|
||||
SYS = 0x1f, //system
|
||||
};
|
||||
|
||||
inline operator uint32_t() const {
|
||||
return m << 0 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
|
||||
}
|
||||
|
||||
inline auto operator=(uint32 data) -> PSR& {
|
||||
m = data.bit(0,4);
|
||||
t = data.bit(5);
|
||||
f = data.bit(6);
|
||||
i = data.bit(7);
|
||||
v = data.bit(28);
|
||||
c = data.bit(29);
|
||||
z = data.bit(30);
|
||||
n = data.bit(31);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint5 m; //mode
|
||||
boolean t; //thumb
|
||||
boolean f; //fiq
|
||||
boolean i; //irq
|
||||
boolean v; //overflow
|
||||
boolean c; //carry
|
||||
boolean z; //zero
|
||||
boolean n; //negative
|
||||
};
|
||||
|
||||
struct Processor {
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
GPR r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
|
||||
PSR cpsr;
|
||||
|
||||
struct FIQ {
|
||||
GPR r8, r9, r10, r11, r12, r13, r14;
|
||||
PSR spsr;
|
||||
} fiq;
|
||||
|
||||
struct IRQ {
|
||||
GPR r13, r14;
|
||||
PSR spsr;
|
||||
} irq;
|
||||
|
||||
struct SVC {
|
||||
GPR r13, r14;
|
||||
PSR spsr;
|
||||
} svc;
|
||||
|
||||
struct ABT {
|
||||
GPR r13, r14;
|
||||
PSR spsr;
|
||||
} abt;
|
||||
|
||||
struct UND {
|
||||
GPR r13, r14;
|
||||
PSR spsr;
|
||||
} und;
|
||||
} processor;
|
||||
|
||||
struct Pipeline {
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Instruction {
|
||||
uint32 address;
|
||||
uint32 instruction;
|
||||
boolean thumb; //not used by fetch stage
|
||||
};
|
||||
|
||||
uint1 reload = 1;
|
||||
uint1 nonsequential = 1;
|
||||
Instruction fetch;
|
||||
Instruction decode;
|
||||
Instruction execute;
|
||||
} pipeline;
|
||||
|
||||
uint32 opcode;
|
||||
boolean carry;
|
||||
boolean irq;
|
||||
|
||||
function<void (uint32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
|
||||
//disassembler.cpp
|
||||
auto armDisassembleBranch(int24, uint1) -> string;
|
||||
auto armDisassembleBranchExchangeRegister(uint4) -> string;
|
||||
auto armDisassembleDataImmediate(uint8, uint4, uint4, uint4, uint1, uint4) -> string;
|
||||
auto armDisassembleDataImmediateShift(uint4, uint2, uint5, uint4, uint4, uint1, uint4) -> string;
|
||||
auto armDisassembleDataRegisterShift(uint4, uint2, uint4, uint4, uint4, uint1, uint4) -> string;
|
||||
auto armDisassembleLoadImmediate(uint8, uint1, uint4, uint4, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleLoadRegister(uint4, uint1, uint4, uint4, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMemorySwap(uint4, uint4, uint4, uint1) -> string;
|
||||
auto armDisassembleMoveHalfImmediate(uint8, uint4, uint4, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveHalfRegister(uint4, uint4, uint4, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveImmediateOffset(uint12, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveMultiple(uint16, uint4, uint1, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveRegisterOffset(uint4, uint2, uint5, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveToRegisterFromStatus(uint4, uint1) -> string;
|
||||
auto armDisassembleMoveToStatusFromImmediate(uint8, uint4, uint4, uint1) -> string;
|
||||
auto armDisassembleMoveToStatusFromRegister(uint4, uint4, uint1) -> string;
|
||||
auto armDisassembleMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> string;
|
||||
auto armDisassembleMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleSoftwareInterrupt(uint24) -> string;
|
||||
auto armDisassembleUndefined() -> string;
|
||||
|
||||
auto thumbDisassembleALU(uint3, uint3, uint4) -> string;
|
||||
auto thumbDisassembleALUExtended(uint4, uint4, uint2) -> string;
|
||||
auto thumbDisassembleAddRegister(uint8, uint3, uint1) -> string;
|
||||
auto thumbDisassembleAdjustImmediate(uint3, uint3, uint3, uint1) -> string;
|
||||
auto thumbDisassembleAdjustRegister(uint3, uint3, uint3, uint1) -> string;
|
||||
auto thumbDisassembleAdjustStack(uint7, uint1) -> string;
|
||||
auto thumbDisassembleBranchExchange(uint4) -> string;
|
||||
auto thumbDisassembleBranchFarPrefix(int11) -> string;
|
||||
auto thumbDisassembleBranchFarSuffix(uint11) -> string;
|
||||
auto thumbDisassembleBranchNear(int11) -> string;
|
||||
auto thumbDisassembleBranchTest(int8, uint4) -> string;
|
||||
auto thumbDisassembleImmediate(uint8, uint3, uint2) -> string;
|
||||
auto thumbDisassembleLoadLiteral(uint8, uint3) -> string;
|
||||
auto thumbDisassembleMoveByteImmediate(uint3, uint3, uint5, uint1) -> string;
|
||||
auto thumbDisassembleMoveHalfImmediate(uint3, uint3, uint5, uint1) -> string;
|
||||
auto thumbDisassembleMoveMultiple(uint8, uint3, uint1) -> string;
|
||||
auto thumbDisassembleMoveRegisterOffset(uint3, uint3, uint3, uint3) -> string;
|
||||
auto thumbDisassembleMoveStack(uint8, uint3, uint1) -> string;
|
||||
auto thumbDisassembleMoveWordImmediate(uint3, uint3, uint5, uint1) -> string;
|
||||
auto thumbDisassembleShiftImmediate(uint3, uint3, uint5, uint2) -> string;
|
||||
auto thumbDisassembleSoftwareInterrupt(uint8) -> string;
|
||||
auto thumbDisassembleStackMultiple(uint8, uint1, uint1) -> string;
|
||||
auto thumbDisassembleUndefined() -> string;
|
||||
|
||||
function<string (uint32 opcode)> armDisassemble[4096];
|
||||
function<string ()> thumbDisassemble[65536];
|
||||
|
||||
uint32 _pc;
|
||||
string _c;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,413 +0,0 @@
|
||||
static const string _r[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"
|
||||
};
|
||||
static const string _conditions[] = {
|
||||
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "", "nv",
|
||||
};
|
||||
#define _s save ? "s" : ""
|
||||
#define _move(mode) (mode == 13 || mode == 15)
|
||||
#define _comp(mode) (mode >= 8 && mode <= 11)
|
||||
#define _math(mode) (mode <= 7 || mode == 12 || mode == 14)
|
||||
|
||||
auto ARM7TDMI::disassembleInstruction(maybe<uint32> pc, maybe<boolean> thumb) -> string {
|
||||
if(!pc) pc = pipeline.execute.address;
|
||||
if(!thumb) thumb = cpsr().t;
|
||||
|
||||
_pc = pc();
|
||||
if(!thumb()) {
|
||||
uint32 opcode = read(Word | Nonsequential, _pc & ~3);
|
||||
uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
_c = _conditions[opcode >> 28];
|
||||
return pad(armDisassemble[index](opcode), -40);
|
||||
} else {
|
||||
uint16 opcode = read(Half | Nonsequential, _pc & ~1);
|
||||
return pad(thumbDisassemble[opcode](), -40);
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::disassembleContext() -> string {
|
||||
string output;
|
||||
for(uint n : range(16)) {
|
||||
output.append(_r[n], ":", hex(r(n), 8L), " ");
|
||||
}
|
||||
|
||||
output.append("cpsr:");
|
||||
output.append(cpsr().n ? "N" : "n");
|
||||
output.append(cpsr().z ? "Z" : "z");
|
||||
output.append(cpsr().c ? "C" : "c");
|
||||
output.append(cpsr().v ? "V" : "v", "/");
|
||||
output.append(cpsr().i ? "I" : "i");
|
||||
output.append(cpsr().f ? "F" : "f");
|
||||
output.append(cpsr().t ? "T" : "t", "/");
|
||||
output.append(hex(cpsr().m, 2L));
|
||||
if(cpsr().m == PSR::USR || cpsr().m == PSR::SYS) return output;
|
||||
|
||||
output.append(" spsr:");
|
||||
output.append(spsr().n ? "N" : "n");
|
||||
output.append(spsr().z ? "Z" : "z");
|
||||
output.append(spsr().c ? "C" : "c");
|
||||
output.append(spsr().v ? "V" : "v", "/");
|
||||
output.append(spsr().i ? "I" : "i");
|
||||
output.append(spsr().f ? "F" : "f");
|
||||
output.append(spsr().t ? "T" : "t", "/");
|
||||
output.append(hex(spsr().m, 2L));
|
||||
return output;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::armDisassembleBranch
|
||||
(int24 displacement, uint1 link) -> string {
|
||||
return {"b", link ? "l" : "", _c, " 0x", hex(_pc + 8 + displacement * 4, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleBranchExchangeRegister
|
||||
(uint4 m) -> string {
|
||||
return {"bx", _c, " ", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleDataImmediate
|
||||
(uint8 immediate, uint4 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> string {
|
||||
static const string opcode[] = {
|
||||
"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
|
||||
"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
|
||||
};
|
||||
uint32 data = immediate >> (shift << 1) | immediate << 32 - (shift << 1);
|
||||
return {opcode[mode], _c,
|
||||
_move(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
_comp(mode) ? string{" ", _r[n]} : string{},
|
||||
_math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
",#0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleDataImmediateShift
|
||||
(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> string {
|
||||
static const string opcode[] = {
|
||||
"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
|
||||
"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
|
||||
};
|
||||
return {opcode[mode], _c,
|
||||
_move(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
_comp(mode) ? string{" ", _r[n]} : string{},
|
||||
_math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
",", _r[m],
|
||||
type == 0 && shift ? string{" lsl #", shift} : string{},
|
||||
type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{},
|
||||
type == 2 ? string{" asr #", shift ? (uint)shift : 32} : string{},
|
||||
type == 3 && shift ? string{" ror #", shift} : string{},
|
||||
type == 3 && !shift ? " rrx" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleDataRegisterShift
|
||||
(uint4 m, uint2 type, uint4 s, uint4 d, uint4 n, uint1 save, uint4 mode) -> string {
|
||||
static const string opcode[] = {
|
||||
"and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc",
|
||||
"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
|
||||
};
|
||||
return {opcode[mode], _c,
|
||||
_move(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
_comp(mode) ? string{" ", _r[n]} : string{},
|
||||
_math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
",", _r[m], " ",
|
||||
type == 0 ? "lsl" : "",
|
||||
type == 1 ? "lsr" : "",
|
||||
type == 2 ? "asr" : "",
|
||||
type == 3 ? "ror" : "",
|
||||
" ", _r[s]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadImmediate
|
||||
(uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(read((half ? Half : Byte) | Nonsequential,
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadRegister
|
||||
(uint4 m, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMemorySwap
|
||||
(uint4 m, uint4 d, uint4 n, uint1 byte) -> string {
|
||||
return {"swp", _c, byte ? "b" : "", " ", _r[d], ",", _r[m], ",[", _r[n], "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveHalfImmediate
|
||||
(uint8 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(read(Half | Nonsequential, _pc + (up ? +immediate : -immediate)), 4L)};
|
||||
|
||||
return {mode ? "ldr" : "str", _c, "h ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveHalfRegister
|
||||
(uint4 m, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
return {mode ? "ldr" : "str", _c, "h ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveImmediateOffset
|
||||
(uint12 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(read((byte ? Byte : Word) | Nonsequential,
|
||||
_pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)};
|
||||
return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 3L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveMultiple
|
||||
(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> string {
|
||||
string registers;
|
||||
for(uint index : range(16)) {
|
||||
if(list.bit(index)) registers.append(_r[index], ",");
|
||||
}
|
||||
registers.trimRight(",", 1L);
|
||||
return {mode ? "ldm" : "stm", _c,
|
||||
up == 0 && pre == 0 ? "da" : "",
|
||||
up == 0 && pre == 1 ? "db" : "",
|
||||
up == 1 && pre == 0 ? "ia" : "",
|
||||
up == 1 && pre == 1 ? "ib" : "",
|
||||
" ", _r[n], writeback ? "!" : "",
|
||||
",{", registers, "}", type ? "^" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveRegisterOffset
|
||||
(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> string {
|
||||
return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
type == 0 && shift ? string{" lsl #", shift} : string{},
|
||||
type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{},
|
||||
type == 2 ? string{" asr #", shift ? (uint)shift : 32} : string{},
|
||||
type == 3 && shift ? string{" ror #", shift} : string{},
|
||||
type == 3 && !shift ? " rrx" : "",
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus
|
||||
(uint4 d, uint1 mode) -> string {
|
||||
return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToStatusFromImmediate
|
||||
(uint8 immediate, uint4 rotate, uint4 field, uint1 mode) -> string {
|
||||
uint32 data = immediate >> (rotate << 1) | immediate << 32 - (rotate << 1);
|
||||
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
|
||||
field.bit(0) ? "c" : "",
|
||||
field.bit(1) ? "x" : "",
|
||||
field.bit(2) ? "s" : "",
|
||||
field.bit(3) ? "f" : "",
|
||||
",#0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToStatusFromRegister
|
||||
(uint4 m, uint4 field, uint1 mode) -> string {
|
||||
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
|
||||
field.bit(0) ? "c" : "",
|
||||
field.bit(1) ? "x" : "",
|
||||
field.bit(2) ? "s" : "",
|
||||
field.bit(3) ? "f" : "",
|
||||
",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMultiply
|
||||
(uint4 m, uint4 s, uint4 n, uint4 d, uint1 save, uint1 accumulate) -> string {
|
||||
if(accumulate) {
|
||||
return {"mla", _c, _s, " ", _r[d], ",", _r[m], ",", _r[s], ",", _r[n]};
|
||||
} else {
|
||||
return {"mul", _c, _s, " ", _r[d], ",", _r[m], ",", _r[s]};
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMultiplyLong
|
||||
(uint4 m, uint4 s, uint4 l, uint4 h, uint1 save, uint1 accumulate, uint1 sign) -> string {
|
||||
return {sign ? "s" : "u", accumulate ? "mlal" : "mull", _c, _s, " ",
|
||||
_r[l], ",", _r[h], ",", _r[m], ",", _r[s]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleSoftwareInterrupt
|
||||
(uint24 immediate) -> string {
|
||||
return {"swi #0x", hex(immediate, 6L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleUndefined
|
||||
() -> string {
|
||||
return {"undefined"};
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleALU
|
||||
(uint3 d, uint3 m, uint4 mode) -> string {
|
||||
static const string opcode[] = {
|
||||
"and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
|
||||
"tst", "neg", "cmp", "cmn", "orr", "mul", "bic", "mvn",
|
||||
};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleALUExtended
|
||||
(uint4 d, uint4 m, uint2 mode) -> string {
|
||||
static const string opcode[] = {"add", "sub", "mov"};
|
||||
if(d == 8 && m == 8 && mode == 2) return {"nop"};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAddRegister
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> string {
|
||||
return {"add ", _r[d], ",", mode ? "sp" : "pc", ",#0x", hex(immediate, 2L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAdjustImmediate
|
||||
(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> string {
|
||||
return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",#", immediate};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAdjustRegister
|
||||
(uint3 d, uint3 n, uint3 m, uint1 mode) -> string {
|
||||
return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAdjustStack
|
||||
(uint7 immediate, uint1 mode) -> string {
|
||||
return {!mode ? "add" : "sub", " sp,#0x", hex(immediate * 4, 3L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchExchange
|
||||
(uint4 m) -> string {
|
||||
return {"bx ", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchFarPrefix
|
||||
(int11 displacementHi) -> string {
|
||||
uint11 displacementLo = read(Half | Nonsequential, (_pc & ~1) + 2);
|
||||
int22 displacement = displacementHi << 11 | displacementLo << 0;
|
||||
uint32 address = _pc + 4 + displacement * 2;
|
||||
return {"bl 0x", hex(address, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchFarSuffix
|
||||
(uint11 displacement) -> string {
|
||||
return {"bl (suffix)"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchNear
|
||||
(int11 displacement) -> string {
|
||||
uint32 address = _pc + 4 + displacement * 2;
|
||||
return {"b 0x", hex(address, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchTest
|
||||
(int8 displacement, uint4 condition) -> string {
|
||||
uint32 address = _pc + 4 + displacement * 2;
|
||||
return {"b", _conditions[condition], " 0x", hex(address, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleImmediate
|
||||
(uint8 immediate, uint3 d, uint2 mode) -> string {
|
||||
static const string opcode[] = {"mov", "cmp", "add", "sub"};
|
||||
return {opcode[mode], " ", _r[d], ",#0x", hex(immediate, 2L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleLoadLiteral
|
||||
(uint8 displacement, uint3 d) -> string {
|
||||
uint32 address = ((_pc + 4) & ~3) + (displacement << 2);
|
||||
uint32 data = read(Word | Nonsequential, address);
|
||||
return {"ldr ", _r[d], ",[pc,#0x", hex(address, 8L), "] =0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveByteImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string {
|
||||
return {mode ? "ldrb" : "strb", " ", _r[d], ",[", _r[n], ",#0x", hex(offset, 2L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveHalfImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string {
|
||||
return {mode ? "ldrh" : "strh", " ", _r[d], ",[", _r[n], ",#0x", hex(offset * 2, 2L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveMultiple
|
||||
(uint8 list, uint3 n, uint1 mode) -> string {
|
||||
string registers;
|
||||
for(uint m : range(8)) {
|
||||
if(list.bit(m)) registers.append(_r[m], ",");
|
||||
}
|
||||
registers.trimRight(",", 1L);
|
||||
return {mode ? "ldmia" : "stmia", " ", _r[n], "!,{", registers, "}"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveRegisterOffset
|
||||
(uint3 d, uint3 n, uint3 m, uint3 mode) -> string {
|
||||
static const string opcode[] = {"str", "strh", "strb", "ldsb", "ldr", "ldrh", "ldrb", "ldsh"};
|
||||
return {opcode[mode], " ", _r[d], ",[", _r[n], ",", _r[m], "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveStack
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> string {
|
||||
return {mode ? "ldr" : "str", " ", _r[d], ",[sp,#0x", hex(immediate * 4, 3L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveWordImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string {
|
||||
return {mode ? "ldr" : "str", " ", _r[d], ",[", _r[n], ",#0x", hex(offset * 4, 2L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleShiftImmediate
|
||||
(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> string {
|
||||
static const string opcode[] = {"lsl", "lsr", "asr"};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m], ",#", immediate};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleSoftwareInterrupt
|
||||
(uint8 immediate) -> string {
|
||||
return {"swi #0x", hex(immediate, 2L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleStackMultiple
|
||||
(uint8 list, uint1 lrpc, uint1 mode) -> string {
|
||||
string registers;
|
||||
for(uint m : range(8)) {
|
||||
if(list.bit(m)) registers.append(_r[m], ",");
|
||||
}
|
||||
if(lrpc) registers.append(!mode ? "lr," : "pc,");
|
||||
registers.trimRight(",", 1L);
|
||||
return {!mode ? "push" : "pop", " {", registers, "}"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleUndefined
|
||||
() -> string {
|
||||
return {"undefined"};
|
||||
}
|
||||
|
||||
#undef _s
|
||||
#undef _move
|
||||
#undef _comp
|
||||
#undef _save
|
||||
@@ -1,538 +0,0 @@
|
||||
auto ARM7TDMI::fetch() -> void {
|
||||
pipeline.execute = pipeline.decode;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.decode.thumb = cpsr().t;
|
||||
|
||||
uint sequential = Sequential;
|
||||
if(pipeline.nonsequential) {
|
||||
pipeline.nonsequential = false;
|
||||
sequential = Nonsequential;
|
||||
}
|
||||
|
||||
uint mask = !cpsr().t ? 3 : 1;
|
||||
uint size = !cpsr().t ? Word : Half;
|
||||
|
||||
r(15).data += size >> 3;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | sequential, pipeline.fetch.address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::instruction() -> void {
|
||||
uint mask = !cpsr().t ? 3 : 1;
|
||||
uint size = !cpsr().t ? Word : Half;
|
||||
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~mask;
|
||||
pipeline.fetch.address = r(15) & ~mask;
|
||||
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
|
||||
fetch();
|
||||
}
|
||||
fetch();
|
||||
|
||||
if(irq && !cpsr().i) {
|
||||
exception(PSR::IRQ, 0x18);
|
||||
if(pipeline.execute.thumb) r(14).data += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
opcode = pipeline.execute.instruction;
|
||||
if(!pipeline.execute.thumb) {
|
||||
if(!TST(opcode.bit(28,31))) return;
|
||||
uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
armInstruction[index](opcode);
|
||||
} else {
|
||||
thumbInstruction[(uint16)opcode]();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::exception(uint mode, uint32 address) -> void {
|
||||
auto psr = cpsr();
|
||||
cpsr().m = mode;
|
||||
spsr() = psr;
|
||||
cpsr().t = 0;
|
||||
if(cpsr().m == PSR::FIQ) cpsr().f = 1;
|
||||
cpsr().i = 1;
|
||||
r(14) = pipeline.decode.address;
|
||||
r(15) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInitialize() -> void {
|
||||
#define bind(id, name, ...) { \
|
||||
uint index = (id & 0x0ff00000) >> 16 | (id & 0x000000f0) >> 4; \
|
||||
assert(!armInstruction[index]); \
|
||||
armInstruction[index] = [&](uint32 opcode) { return armInstruction##name(arguments); }; \
|
||||
armDisassemble[index] = [&](uint32 opcode) { return armDisassemble##name(arguments); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
std::integral_constant<uint32_t, bit::test(s)>::value
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0,23), /* displacement */ \
|
||||
opcode.bit(24) /* link */
|
||||
for(uint4 displacementLo : range(16))
|
||||
for(uint4 displacementHi : range(16))
|
||||
for(uint1 link : range(2)) {
|
||||
auto opcode = pattern(".... 101? ???? ???? ???? ???? ???? ????")
|
||||
| displacementLo << 4 | displacementHi << 20 | link << 24;
|
||||
bind(opcode, Branch);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) /* m */
|
||||
{
|
||||
auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????");
|
||||
bind(opcode, BranchExchangeRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 7), /* immediate */ \
|
||||
opcode.bit( 8,11), /* shift */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21,24) /* mode */
|
||||
for(uint4 shiftHi : range(16))
|
||||
for(uint1 save : range(2))
|
||||
for(uint4 mode : range(16)) {
|
||||
if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN
|
||||
auto opcode = pattern(".... 001? ???? ???? ???? ???? ???? ????") | shiftHi << 4 | save << 20 | mode << 21;
|
||||
bind(opcode, DataImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5, 6), /* type */ \
|
||||
opcode.bit( 7,11), /* shift */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21,24) /* mode */
|
||||
for(uint2 type : range(4))
|
||||
for(uint1 shiftLo : range(2))
|
||||
for(uint1 save : range(2))
|
||||
for(uint4 mode : range(16)) {
|
||||
if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN
|
||||
auto opcode = pattern(".... 000? ???? ???? ???? ???? ???0 ????") | type << 5 | shiftLo << 7 | save << 20 | mode << 21;
|
||||
bind(opcode, DataImmediateShift);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5, 6), /* type */ \
|
||||
opcode.bit( 8,11), /* s */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21,24) /* mode */
|
||||
for(uint2 type : range(4))
|
||||
for(uint1 save : range(2))
|
||||
for(uint4 mode : range(16)) {
|
||||
if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN
|
||||
auto opcode = pattern(".... 000? ???? ???? ???? ???? 0??1 ????") | type << 5 | save << 20 | mode << 21;
|
||||
bind(opcode, DataRegisterShift);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint1 half : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?1 ???? ???? ???? 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5), /* half */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint1 half : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?1 ???? ???? ---- 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(22) /* byte */
|
||||
for(uint1 byte : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22;
|
||||
bind(opcode, MemorySwap);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?? ???? ???? ???? 1011 ????") | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveHalfImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?? ???? ???? ---- 1011 ????") | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveHalfRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0,11), /* immediate */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(22), /* byte */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint4 immediatePart : range(16))
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 byte : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 010? ???? ???? ???? ???? ???? ????")
|
||||
| immediatePart << 4 | mode << 20 | writeback << 21 | byte << 22 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveImmediateOffset);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0,15), /* list */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(22), /* type */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint4 listPart : range(16))
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 type : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 100? ???? ???? ???? ???? ???? ????")
|
||||
| listPart << 4 | mode << 20 | writeback << 21 | type << 22 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveMultiple);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 5, 6), /* type */ \
|
||||
opcode.bit( 7,11), /* shift */ \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(16,19), /* n */ \
|
||||
opcode.bit(20), /* mode */ \
|
||||
opcode.bit(21), /* writeback */ \
|
||||
opcode.bit(22), /* byte */ \
|
||||
opcode.bit(23), /* up */ \
|
||||
opcode.bit(24) /* pre */
|
||||
for(uint2 type : range(4))
|
||||
for(uint1 shiftLo : range(2))
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 byte : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 011? ???? ???? ???? ???? ???0 ????")
|
||||
| type << 5 | shiftLo << 7 | mode << 20 | writeback << 21 | byte << 22 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveRegisterOffset);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit(12,15), /* d */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22;
|
||||
bind(opcode, MoveToRegisterFromStatus);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 7), /* immediate */ \
|
||||
opcode.bit( 8,11), /* rotate */ \
|
||||
opcode.bit(16,19), /* field */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(uint4 immediateHi : range(16))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0011 0?10 ???? ---- ???? ???? ????") | immediateHi << 4 | mode << 22;
|
||||
bind(opcode, MoveToStatusFromImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit(16,19), /* field */ \
|
||||
opcode.bit(22) /* mode */
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22;
|
||||
bind(opcode, MoveToStatusFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 8,11), /* s */ \
|
||||
opcode.bit(12,15), /* n */ \
|
||||
opcode.bit(16,19), /* d */ \
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21) /* accumulate */
|
||||
for(uint1 save : range(2))
|
||||
for(uint1 accumulate : range(2)) {
|
||||
auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21;
|
||||
bind(opcode, Multiply);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0, 3), /* m */ \
|
||||
opcode.bit( 8,11), /* s */ \
|
||||
opcode.bit(12,15), /* l */ \
|
||||
opcode.bit(16,19), /* h */ \
|
||||
opcode.bit(20), /* save */ \
|
||||
opcode.bit(21), /* accumulate */ \
|
||||
opcode.bit(22) /* sign */
|
||||
for(uint1 save : range(2))
|
||||
for(uint1 accumulate : range(2))
|
||||
for(uint1 sign : range(2)) {
|
||||
auto opcode = pattern(".... 0000 1??? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21 | sign << 22;
|
||||
bind(opcode, MultiplyLong);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bit( 0,23) /* immediate */
|
||||
for(uint4 immediateLo : range(16))
|
||||
for(uint4 immediateHi : range(16)) {
|
||||
auto opcode = pattern(".... 1111 ???? ???? ???? ???? ???? ????") | immediateLo << 4 | immediateHi << 20;
|
||||
bind(opcode, SoftwareInterrupt);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments
|
||||
for(uint12 id : range(4096)) {
|
||||
if(armInstruction[id]) continue;
|
||||
auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | id.bit(0,3) << 4 | id.bit(4,11) << 20;
|
||||
bind(opcode, Undefined);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInitialize() -> void {
|
||||
#define bind(id, name, ...) { \
|
||||
assert(!thumbInstruction[id]); \
|
||||
thumbInstruction[id] = [=] { return thumbInstruction##name(__VA_ARGS__); }; \
|
||||
thumbDisassemble[id] = [=] { return thumbDisassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
std::integral_constant<uint16_t, bit::test(s)>::value
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint4 mode : range(16)) {
|
||||
auto opcode = pattern("0100 00?? ???? ????") | d << 0 | m << 3 | mode << 6;
|
||||
bind(opcode, ALU, d, m, mode);
|
||||
}
|
||||
|
||||
for(uint4 d : range(16))
|
||||
for(uint4 m : range(16))
|
||||
for(uint2 mode : range(4)) {
|
||||
if(mode == 3) continue;
|
||||
auto opcode = pattern("0100 01?? ???? ????") | d.bit(0,2) << 0 | m << 3 | d.bit(3) << 7 | mode << 8;
|
||||
bind(opcode, ALUExtended, d, m, mode);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256))
|
||||
for(uint3 d : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1010 ???? ???? ????") | immediate << 0 | d << 8 | mode << 11;
|
||||
bind(opcode, AddRegister, immediate, d, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint3 immediate : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0001 11?? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 9;
|
||||
bind(opcode, AdjustImmediate, d, n, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0001 10?? ???? ????") | d << 0 | n << 3 | m << 6 | mode << 9;
|
||||
bind(opcode, AdjustRegister, d, n, m, mode);
|
||||
}
|
||||
|
||||
for(uint7 immediate : range(128))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1011 0000 ???? ????") | immediate << 0 | mode << 7;
|
||||
bind(opcode, AdjustStack, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint3 _ : range(8))
|
||||
for(uint4 m : range(16)) {
|
||||
auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3;
|
||||
bind(opcode, BranchExchange, m);
|
||||
}
|
||||
|
||||
for(uint11 displacement : range(2048)) {
|
||||
auto opcode = pattern("1111 0??? ???? ????") | displacement << 0;
|
||||
bind(opcode, BranchFarPrefix, displacement);
|
||||
}
|
||||
|
||||
for(uint11 displacement : range(2048)) {
|
||||
auto opcode = pattern("1111 1??? ???? ????") | displacement << 0;
|
||||
bind(opcode, BranchFarSuffix, displacement);
|
||||
}
|
||||
|
||||
for(uint11 displacement : range(2048)) {
|
||||
auto opcode = pattern("1110 0??? ???? ????") | displacement << 0;
|
||||
bind(opcode, BranchNear, displacement);
|
||||
}
|
||||
|
||||
for(uint8 displacement : range(256))
|
||||
for(uint4 condition : range(16)) {
|
||||
if(condition == 15) continue; //BNV
|
||||
auto opcode = pattern("1101 ???? ???? ????") | displacement << 0 | condition << 8;
|
||||
bind(opcode, BranchTest, displacement, condition);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256))
|
||||
for(uint3 d : range(8))
|
||||
for(uint2 mode : range(4)) {
|
||||
auto opcode = pattern("001? ???? ???? ????") | immediate << 0 | d << 8 | mode << 11;
|
||||
bind(opcode, Immediate, immediate, d, mode);
|
||||
}
|
||||
|
||||
for(uint8 displacement : range(256))
|
||||
for(uint3 d : range(8)) {
|
||||
auto opcode = pattern("0100 1??? ???? ????") | displacement << 0 | d << 8;
|
||||
bind(opcode, LoadLiteral, displacement, d);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint5 immediate : range(32))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0111 ???? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 11;
|
||||
bind(opcode, MoveByteImmediate, d, n, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint5 immediate : range(32))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1000 ???? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 11;
|
||||
bind(opcode, MoveHalfImmediate, d, n, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint8 list : range(256))
|
||||
for(uint3 n : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1100 ???? ???? ????") | list << 0 | n << 8 | mode << 11;
|
||||
bind(opcode, MoveMultiple, list, n, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint3 mode : range(8)) {
|
||||
auto opcode = pattern("0101 ???? ???? ????") | d << 0 | n << 3 | m << 6 | mode << 9;
|
||||
bind(opcode, MoveRegisterOffset, d, n, m, mode);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256))
|
||||
for(uint3 d : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1001 ???? ???? ????") | immediate << 0 | d << 8 | mode << 11;
|
||||
bind(opcode, MoveStack, immediate, d, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint5 offset : range(32))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0110 ???? ???? ????") | d << 0 | n << 3 | offset << 6 | mode << 11;
|
||||
bind(opcode, MoveWordImmediate, d, n, offset, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint5 immediate : range(32))
|
||||
for(uint2 mode : range(4)) {
|
||||
if(mode == 3) continue;
|
||||
auto opcode = pattern("000? ???? ???? ????") | d << 0 | m << 3 | immediate << 6 | mode << 11;
|
||||
bind(opcode, ShiftImmediate, d, m, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256)) {
|
||||
auto opcode = pattern("1101 1111 ???? ????") | immediate << 0;
|
||||
bind(opcode, SoftwareInterrupt, immediate);
|
||||
}
|
||||
|
||||
for(uint8 list : range(256))
|
||||
for(uint1 lrpc : range(2))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1011 ?10? ???? ????") | list << 0 | lrpc << 8 | mode << 11;
|
||||
bind(opcode, StackMultiple, list, lrpc, mode);
|
||||
}
|
||||
|
||||
for(uint16 id : range(65536)) {
|
||||
if(thumbInstruction[id]) continue;
|
||||
auto opcode = pattern("???? ???? ???? ????") | id << 0;
|
||||
bind(opcode, Undefined);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
auto ARM7TDMI::armALU(uint4 mode, uint4 d, uint4 n, uint32 rm) -> void {
|
||||
uint32 rn = r(n);
|
||||
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(rn & rm); break; //AND
|
||||
case 1: r(d) = BIT(rn ^ rm); break; //EOR
|
||||
case 2: r(d) = SUB(rn, rm, 1); break; //SUB
|
||||
case 3: r(d) = SUB(rm, rn, 1); break; //RSB
|
||||
case 4: r(d) = ADD(rn, rm, 0); break; //ADD
|
||||
case 5: r(d) = ADD(rn, rm, cpsr().c); break; //ADC
|
||||
case 6: r(d) = SUB(rn, rm, cpsr().c); break; //SBC
|
||||
case 7: r(d) = SUB(rm, rn, cpsr().c); break; //RSC
|
||||
case 8: BIT(rn & rm); break; //TST
|
||||
case 9: BIT(rn ^ rm); break; //TEQ
|
||||
case 10: SUB(rn, rm, 1); break; //CMP
|
||||
case 11: ADD(rn, rm, 0); break; //CMN
|
||||
case 12: r(d) = BIT(rn | rm); break; //ORR
|
||||
case 13: r(d) = BIT(rm); break; //MOV
|
||||
case 14: r(d) = BIT(rn & ~rm); break; //BIC
|
||||
case 15: r(d) = BIT(~rm); break; //MVN
|
||||
}
|
||||
|
||||
if(exception() && d == 15 && opcode.bit(20)) {
|
||||
cpsr() = spsr();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void {
|
||||
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
|
||||
PSR& psr = mode ? spsr() : cpsr();
|
||||
|
||||
if(field.bit(0)) {
|
||||
if(mode || privileged()) {
|
||||
psr.m = data.bit(0,4);
|
||||
psr.t = data.bit(5);
|
||||
psr.f = data.bit(6);
|
||||
psr.i = data.bit(7);
|
||||
if(!mode && psr.t) r(15).data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(field.bit(3)) {
|
||||
psr.v = data.bit(28);
|
||||
psr.c = data.bit(29);
|
||||
psr.z = data.bit(30);
|
||||
psr.n = data.bit(31);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::armInstructionBranch
|
||||
(int24 displacement, uint1 link) -> void {
|
||||
if(link) r(14) = r(15) - 4;
|
||||
r(15) = r(15) + displacement * 4;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionBranchExchangeRegister
|
||||
(uint4 m) -> void {
|
||||
uint32 address = r(m);
|
||||
cpsr().t = address.bit(0);
|
||||
r(15) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionDataImmediate
|
||||
(uint8 immediate, uint4 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> void {
|
||||
uint32 data = immediate;
|
||||
carry = cpsr().c;
|
||||
if(shift) data = ROR(data, shift << 1);
|
||||
armALU(mode, d, n, data);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionDataImmediateShift
|
||||
(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> void {
|
||||
uint32 rm = r(m);
|
||||
carry = cpsr().c;
|
||||
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, shift); break;
|
||||
case 1: rm = LSR(rm, shift ? (uint)shift : 32); break;
|
||||
case 2: rm = ASR(rm, shift ? (uint)shift : 32); break;
|
||||
case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break;
|
||||
}
|
||||
|
||||
armALU(mode, d, n, rm);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionDataRegisterShift
|
||||
(uint4 m, uint2 type, uint4 s, uint4 d, uint4 n, uint1 save, uint4 mode) -> void {
|
||||
uint8 rs = r(s) + (s == 15 ? 4 : 0);
|
||||
uint32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||
carry = cpsr().c;
|
||||
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, rs < 33 ? rs : (uint8)33); break;
|
||||
case 1: rm = LSR(rm, rs < 33 ? rs : (uint8)33); break;
|
||||
case 2: rm = ASR(rm, rs < 32 ? rs : (uint8)32); break;
|
||||
case 3: if(rs) rm = ROR(rm, rs & 31 ? uint(rs & 31) : 32); break;
|
||||
}
|
||||
|
||||
armALU(mode, d, n, rm);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadImmediate
|
||||
(uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadRegister
|
||||
(uint4 m, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rm = r(m);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMemorySwap
|
||||
(uint4 m, uint4 d, uint4 n, uint1 byte) -> void {
|
||||
uint32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
|
||||
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
|
||||
r(d) = word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
(uint8 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
(uint4 m, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rm = r(m);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveImmediateOffset
|
||||
(uint12 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveMultiple
|
||||
(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
if(pre == 0 && up == 1) rn = rn + 0; //IA
|
||||
if(pre == 1 && up == 1) rn = rn + 4; //IB
|
||||
if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB
|
||||
if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA
|
||||
|
||||
if(writeback && mode == 1) {
|
||||
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA,IB
|
||||
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA,DB
|
||||
}
|
||||
|
||||
auto cpsrMode = cpsr().m;
|
||||
bool usr = false;
|
||||
if(type && mode == 1 && !list.bit(15)) usr = true;
|
||||
if(type && mode == 0) usr = true;
|
||||
if(usr) cpsr().m = PSR::USR;
|
||||
|
||||
uint sequential = Nonsequential;
|
||||
for(uint m : range(16)) {
|
||||
if(!list.bit(m)) continue;
|
||||
if(mode == 1) r(m) = read(Word | sequential, rn);
|
||||
if(mode == 0) write(Word | sequential, rn, r(m));
|
||||
rn += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
|
||||
if(usr) cpsr().m = cpsrMode;
|
||||
|
||||
if(mode) {
|
||||
idle();
|
||||
if(type && list.bit(15) && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) {
|
||||
cpsr() = spsr();
|
||||
}
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
}
|
||||
|
||||
if(writeback && mode == 0) {
|
||||
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA,IB
|
||||
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA,DB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveRegisterOffset
|
||||
(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> void {
|
||||
uint32 rm = r(m);
|
||||
uint32 rd = r(d);
|
||||
uint32 rn = r(n);
|
||||
carry = cpsr().c;
|
||||
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, shift); break;
|
||||
case 1: rm = LSR(rm, shift ? (uint)shift : 32); break;
|
||||
case 2: rm = ASR(rm, shift ? (uint)shift : 32); break;
|
||||
case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break;
|
||||
}
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToRegisterFromStatus
|
||||
(uint4 d, uint1 mode) -> void {
|
||||
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
|
||||
r(d) = mode ? spsr() : cpsr();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToStatusFromImmediate
|
||||
(uint8 immediate, uint4 rotate, uint4 field, uint1 mode) -> void {
|
||||
uint32 data = immediate;
|
||||
if(rotate) data = ROR(data, rotate << 1);
|
||||
armMoveToStatus(field, mode, data);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToStatusFromRegister
|
||||
(uint4 m, uint4 field, uint1 mode) -> void {
|
||||
armMoveToStatus(field, mode, r(m));
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiply
|
||||
(uint4 m, uint4 s, uint4 n, uint4 d, uint1 save, uint1 accumulate) -> void {
|
||||
if(accumulate) idle();
|
||||
r(d) = MUL(accumulate ? r(n) : 0, r(m), r(s));
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiplyLong
|
||||
(uint4 m, uint4 s, uint4 l, uint4 h, uint1 save, uint1 accumulate, uint1 sign) -> void {
|
||||
uint64 rm = r(m);
|
||||
uint64 rs = r(s);
|
||||
|
||||
idle();
|
||||
idle();
|
||||
if(accumulate) idle();
|
||||
|
||||
if(sign) {
|
||||
if(rs >> 8 && rs >> 8 != 0xffffff) idle();
|
||||
if(rs >> 16 && rs >> 16 != 0xffff) idle();
|
||||
if(rs >> 24 && rs >> 24 != 0xff) idle();
|
||||
rm = (int32)rm;
|
||||
rs = (int32)rs;
|
||||
} else {
|
||||
if(rs >> 8) idle();
|
||||
if(rs >> 16) idle();
|
||||
if(rs >> 24) idle();
|
||||
}
|
||||
|
||||
uint64 rd = rm * rs;
|
||||
if(accumulate) rd += (uint64)r(h) << 32 | (uint64)r(l) << 0;
|
||||
|
||||
r(h) = rd >> 32;
|
||||
r(l) = rd >> 0;
|
||||
|
||||
if(save) {
|
||||
cpsr().z = rd == 0;
|
||||
cpsr().n = rd.bit(63);
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionSoftwareInterrupt
|
||||
(uint24 immediate) -> void {
|
||||
exception(PSR::SVC, 0x08);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionUndefined
|
||||
() -> void {
|
||||
exception(PSR::UND, 0x04);
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
auto ARM7TDMI::thumbInstructionALU
|
||||
(uint3 d, uint3 m, uint4 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(r(d) & r(m)); break; //AND
|
||||
case 1: r(d) = BIT(r(d) ^ r(m)); break; //EOR
|
||||
case 2: r(d) = BIT(LSL(r(d), r(m))); break; //LSL
|
||||
case 3: r(d) = BIT(LSR(r(d), r(m))); break; //LSR
|
||||
case 4: r(d) = BIT(ASR(r(d), r(m))); break; //ASR
|
||||
case 5: r(d) = ADD(r(d), r(m), cpsr().c); break; //ADC
|
||||
case 6: r(d) = SUB(r(d), r(m), cpsr().c); break; //SBC
|
||||
case 7: r(d) = BIT(ROR(r(d), r(m))); break; //ROR
|
||||
case 8: BIT(r(d) & r(m)); break; //TST
|
||||
case 9: r(d) = SUB(0, r(m), 1); break; //NEG
|
||||
case 10: SUB(r(d), r(m), 1); break; //CMP
|
||||
case 11: ADD(r(d), r(m), 0); break; //CMN
|
||||
case 12: r(d) = BIT(r(d) | r(m)); break; //ORR
|
||||
case 13: r(d) = MUL(0, r(m), r(d)); break; //MUL
|
||||
case 14: r(d) = BIT(r(d) & ~r(m)); break; //BIC
|
||||
case 15: r(d) = BIT(~r(m)); break; //MVN
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionALUExtended
|
||||
(uint4 d, uint4 m, uint2 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = r(d) + r(m); break; //ADD
|
||||
case 1: SUB(r(d), r(m), 1); break; //SUBS
|
||||
case 2: r(d) = r(m); break; //MOV
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAddRegister
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = (r(15) & ~3) + immediate * 4; break; //ADD pc
|
||||
case 1: r(d) = r(13) + immediate * 4; break; //ADD sp
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAdjustImmediate
|
||||
(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = ADD(r(n), immediate, 0); break; //ADD
|
||||
case 1: r(d) = SUB(r(n), immediate, 1); break; //SUB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAdjustRegister
|
||||
(uint3 d, uint3 n, uint3 m, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = ADD(r(n), r(m), 0); break; //ADD
|
||||
case 1: r(d) = SUB(r(n), r(m), 1); break; //SUB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAdjustStack
|
||||
(uint7 immediate, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(13) = r(13) + immediate * 4; break; //ADD
|
||||
case 1: r(13) = r(13) - immediate * 4; break; //SUB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchExchange
|
||||
(uint4 m) -> void {
|
||||
uint32 address = r(m);
|
||||
cpsr().t = address.bit(0);
|
||||
r(15) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchFarPrefix
|
||||
(int11 displacement) -> void {
|
||||
r(14) = r(15) + (displacement * 2 << 11);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchFarSuffix
|
||||
(uint11 displacement) -> void {
|
||||
r(15) = r(14) + (displacement * 2);
|
||||
r(14) = pipeline.decode.address | 1;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchNear
|
||||
(int11 displacement) -> void {
|
||||
r(15) = r(15) + displacement * 2;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchTest
|
||||
(int8 displacement, uint4 condition) -> void {
|
||||
if(!TST(condition)) return;
|
||||
r(15) = r(15) + displacement * 2;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionImmediate
|
||||
(uint8 immediate, uint3 d, uint2 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(immediate); break; //MOV
|
||||
case 1: SUB(r(d), immediate, 1); break; //CMP
|
||||
case 2: r(d) = ADD(r(d), immediate, 0); break; //ADD
|
||||
case 3: r(d) = SUB(r(d), immediate, 1); break; //SUB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionLoadLiteral
|
||||
(uint8 displacement, uint3 d) -> void {
|
||||
uint32 address = (r(15) & ~3) + (displacement << 2);
|
||||
r(d) = load(Word | Nonsequential, address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveByteImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Byte | Nonsequential, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte | Nonsequential, r(n) + offset); break; //LDRB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveHalfImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Half | Nonsequential, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half | Nonsequential, r(n) + offset * 2); break; //LDRH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveMultiple
|
||||
(uint8 list, uint3 n, uint1 mode) -> void {
|
||||
uint32 rn = r(n);
|
||||
|
||||
for(uint m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
switch(mode) {
|
||||
case 0: write(Word | Nonsequential, rn, r(m)); break; //STMIA
|
||||
case 1: r(m) = read(Word | Nonsequential, rn); break; //LDMIA
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(mode == 0 || !list.bit(n)) r(n) = rn;
|
||||
if(mode == 1) idle();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveRegisterOffset
|
||||
(uint3 d, uint3 n, uint3 m, uint3 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
|
||||
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
|
||||
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
|
||||
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
|
||||
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveStack
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(13) + immediate * 4); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveWordImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(n) + offset * 4); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionShiftImmediate
|
||||
(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = BIT(LSL(r(m), immediate)); break; //LSL
|
||||
case 1: r(d) = BIT(LSR(r(m), immediate ? (uint)immediate : 32)); break; //LSR
|
||||
case 2: r(d) = BIT(ASR(r(m), immediate ? (uint)immediate : 32)); break; //ASR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionSoftwareInterrupt
|
||||
(uint8 immediate) -> void {
|
||||
exception(PSR::SVC, 0x08);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionStackMultiple
|
||||
(uint8 list, uint1 lrpc, uint1 mode) -> void {
|
||||
uint32 sp;
|
||||
switch(mode) {
|
||||
case 0: sp = r(13) - (bit::count(list) + lrpc) * 4; break; //PUSH
|
||||
case 1: sp = r(13); //POP
|
||||
}
|
||||
|
||||
uint sequential = Nonsequential;
|
||||
for(uint m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
switch(mode) {
|
||||
case 0: write(Word | sequential, sp, r(m)); break; //PUSH
|
||||
case 1: r(m) = read(Word | sequential, sp); break; //POP
|
||||
}
|
||||
sp += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
|
||||
if(lrpc) {
|
||||
switch(mode) {
|
||||
case 0: write(Word | sequential, sp, r(14)); break; //PUSH
|
||||
case 1: r(15) = read(Word | sequential, sp); break; //POP
|
||||
}
|
||||
sp += 4;
|
||||
}
|
||||
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(13) = r(13) + (bit::count(list) + lrpc) * 4; //POP
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
r(13) = r(13) - (bit::count(list) + lrpc) * 4; //PUSH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionUndefined
|
||||
() -> void {
|
||||
exception(PSR::UND, 0x04);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
auto ARM7TDMI::idle() -> void {
|
||||
pipeline.nonsequential = true;
|
||||
sleep();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::read(uint mode, uint32 address) -> uint32 {
|
||||
return get(mode, address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::load(uint mode, uint32 address) -> uint32 {
|
||||
pipeline.nonsequential = true;
|
||||
auto word = get(Load | mode, address);
|
||||
if(mode & Half) {
|
||||
address &= 1;
|
||||
word = mode & Signed ? (uint32)(int16)word : (uint32)(uint16)word;
|
||||
}
|
||||
if(mode & Byte) {
|
||||
address &= 0;
|
||||
word = mode & Signed ? (uint32)(int8)word : (uint32)(uint8)word;
|
||||
}
|
||||
if(mode & Signed) {
|
||||
word = ASR(word, address.bit(0,1) << 3);
|
||||
} else {
|
||||
word = ROR(word, address.bit(0,1) << 3);
|
||||
}
|
||||
idle();
|
||||
return word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::write(uint mode, uint32 address, uint32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
return set(mode, address, word);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::store(uint mode, uint32 address, uint32 word) -> void {
|
||||
pipeline.nonsequential = true;
|
||||
if(mode & Half) { word &= 0xffff; word |= word << 16; }
|
||||
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||
return set(Store | mode, address, word);
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
auto ARM7TDMI::r(uint4 index) -> GPR& {
|
||||
switch(index) {
|
||||
case 0: return processor.r0;
|
||||
case 1: return processor.r1;
|
||||
case 2: return processor.r2;
|
||||
case 3: return processor.r3;
|
||||
case 4: return processor.r4;
|
||||
case 5: return processor.r5;
|
||||
case 6: return processor.r6;
|
||||
case 7: return processor.r7;
|
||||
case 8: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r8 : processor.r8;
|
||||
case 9: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r9 : processor.r9;
|
||||
case 10: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r10 : processor.r10;
|
||||
case 11: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r11 : processor.r11;
|
||||
case 12: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r12 : processor.r12;
|
||||
case 13: switch(processor.cpsr.m) {
|
||||
case PSR::FIQ: return processor.fiq.r13;
|
||||
case PSR::IRQ: return processor.irq.r13;
|
||||
case PSR::SVC: return processor.svc.r13;
|
||||
case PSR::ABT: return processor.abt.r13;
|
||||
case PSR::UND: return processor.und.r13;
|
||||
default: return processor.r13;
|
||||
}
|
||||
case 14: switch(processor.cpsr.m) {
|
||||
case PSR::FIQ: return processor.fiq.r14;
|
||||
case PSR::IRQ: return processor.irq.r14;
|
||||
case PSR::SVC: return processor.svc.r14;
|
||||
case PSR::ABT: return processor.abt.r14;
|
||||
case PSR::UND: return processor.und.r14;
|
||||
default: return processor.r14;
|
||||
}
|
||||
case 15: return processor.r15;
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::cpsr() -> PSR& {
|
||||
return processor.cpsr;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::spsr() -> PSR& {
|
||||
switch(processor.cpsr.m) {
|
||||
case PSR::FIQ: return processor.fiq.spsr;
|
||||
case PSR::IRQ: return processor.irq.spsr;
|
||||
case PSR::SVC: return processor.svc.spsr;
|
||||
case PSR::ABT: return processor.abt.spsr;
|
||||
case PSR::UND: return processor.und.spsr;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::privileged() const -> bool {
|
||||
return processor.cpsr.m != PSR::USR;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::exception() const -> bool {
|
||||
return privileged() && processor.cpsr.m != PSR::SYS;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
auto ARM7TDMI::serialize(serializer& s) -> void {
|
||||
processor.serialize(s);
|
||||
pipeline.serialize(s);
|
||||
s.boolean(carry);
|
||||
s.boolean(irq);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
|
||||
s.integer(r0.data);
|
||||
s.integer(r1.data);
|
||||
s.integer(r2.data);
|
||||
s.integer(r3.data);
|
||||
s.integer(r4.data);
|
||||
s.integer(r5.data);
|
||||
s.integer(r6.data);
|
||||
s.integer(r7.data);
|
||||
s.integer(r8.data);
|
||||
s.integer(r9.data);
|
||||
s.integer(r10.data);
|
||||
s.integer(r11.data);
|
||||
s.integer(r12.data);
|
||||
s.integer(r13.data);
|
||||
s.integer(r14.data);
|
||||
s.integer(r15.data);
|
||||
cpsr.serialize(s);
|
||||
s.integer(fiq.r8.data);
|
||||
s.integer(fiq.r9.data);
|
||||
s.integer(fiq.r10.data);
|
||||
s.integer(fiq.r11.data);
|
||||
s.integer(fiq.r12.data);
|
||||
s.integer(fiq.r13.data);
|
||||
s.integer(fiq.r14.data);
|
||||
fiq.spsr.serialize(s);
|
||||
s.integer(irq.r13.data);
|
||||
s.integer(irq.r14.data);
|
||||
irq.spsr.serialize(s);
|
||||
s.integer(svc.r13.data);
|
||||
s.integer(svc.r14.data);
|
||||
svc.spsr.serialize(s);
|
||||
s.integer(abt.r13.data);
|
||||
s.integer(abt.r14.data);
|
||||
abt.spsr.serialize(s);
|
||||
s.integer(und.r13.data);
|
||||
s.integer(und.r14.data);
|
||||
und.spsr.serialize(s);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
|
||||
s.integer(m);
|
||||
s.boolean(t);
|
||||
s.boolean(f);
|
||||
s.boolean(i);
|
||||
s.boolean(v);
|
||||
s.boolean(c);
|
||||
s.boolean(z);
|
||||
s.boolean(n);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
|
||||
s.integer(reload);
|
||||
s.integer(nonsequential);
|
||||
s.integer(fetch.address);
|
||||
s.integer(fetch.instruction);
|
||||
s.boolean(fetch.thumb);
|
||||
s.integer(decode.address);
|
||||
s.integer(decode.instruction);
|
||||
s.boolean(decode.thumb);
|
||||
s.integer(execute.address);
|
||||
s.integer(execute.instruction);
|
||||
s.boolean(execute.thumb);
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
auto GSU::disassembleInstruction() -> string {
|
||||
char s[256];
|
||||
disassembleOpcode(s);
|
||||
return pad(s, -14);
|
||||
}
|
||||
|
||||
auto GSU::disassembleContext() -> string {
|
||||
string s;
|
||||
|
||||
for(uint n : range(16)) {
|
||||
s.append("r", n, ":", hex(regs.r[n].data, 4L), " ");
|
||||
}
|
||||
|
||||
s.append("..."); //todo: add SFR flags
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
auto GSU::disassembleOpcode(char* output) -> void {
|
||||
*output = 0;
|
||||
|
||||
switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) {
|
||||
case 0: disassembleALT0(output); break;
|
||||
case 1: disassembleALT1(output); break;
|
||||
case 2: disassembleALT2(output); break;
|
||||
case 3: disassembleALT3(output); break;
|
||||
}
|
||||
|
||||
uint length = strlen(output);
|
||||
while(length++ < 20) strcat(output, " ");
|
||||
}
|
||||
|
||||
#define case4(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3
|
||||
#define case6(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5
|
||||
#define case12(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
|
||||
case id+ 8: case id+ 9: case id+10: case id+11
|
||||
#define case15(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
|
||||
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14
|
||||
#define case16(id) \
|
||||
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
|
||||
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
|
||||
|
||||
#define op0 regs.pipeline
|
||||
#define op1 read((regs.pbr << 16) + regs.r[15] + 0)
|
||||
#define op2 read((regs.pbr << 16) + regs.r[15] + 1)
|
||||
|
||||
auto GSU::disassembleALT0(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
case (0x01): sprintf(t, "nop"); break;
|
||||
case (0x02): sprintf(t, "cache"); break;
|
||||
case (0x03): sprintf(t, "lsr"); break;
|
||||
case (0x04): sprintf(t, "rol"); break;
|
||||
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
|
||||
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
|
||||
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
|
||||
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
|
||||
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
|
||||
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
|
||||
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
|
||||
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
|
||||
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
|
||||
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
|
||||
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
|
||||
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
|
||||
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
|
||||
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
|
||||
case (0x3c): sprintf(t, "loop"); break;
|
||||
case (0x3d): sprintf(t, "alt1"); break;
|
||||
case (0x3e): sprintf(t, "alt2"); break;
|
||||
case (0x3f): sprintf(t, "alt3"); break;
|
||||
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
|
||||
case (0x4c): sprintf(t, "plot"); break;
|
||||
case (0x4d): sprintf(t, "swap"); break;
|
||||
case (0x4e): sprintf(t, "color"); break;
|
||||
case (0x4f): sprintf(t, "not"); break;
|
||||
case16(0x50): sprintf(t, "add r%u", op0 & 15); break;
|
||||
case16(0x60): sprintf(t, "sub r%u", op0 & 15); break;
|
||||
case (0x70): sprintf(t, "merge"); break;
|
||||
case15(0x71): sprintf(t, "and r%u", op0 & 15); break;
|
||||
case16(0x80): sprintf(t, "mult r%u", op0 & 15); break;
|
||||
case (0x90): sprintf(t, "sbk"); break;
|
||||
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
|
||||
case (0x95): sprintf(t, "sex"); break;
|
||||
case (0x96): sprintf(t, "asr"); break;
|
||||
case (0x97): sprintf(t, "ror"); break;
|
||||
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
|
||||
case (0x9e): sprintf(t, "lob"); break;
|
||||
case (0x9f): sprintf(t, "fmult"); break;
|
||||
case16(0xa0): sprintf(t, "ibt r%u,#$%.2x", op0 & 15, op1 & 255); break;
|
||||
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
|
||||
case (0xc0): sprintf(t, "hib"); break;
|
||||
case15(0xc1): sprintf(t, "or r%u", op0 & 15); break;
|
||||
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
|
||||
case (0xdf): sprintf(t, "getc"); break;
|
||||
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
|
||||
case (0xef): sprintf(t, "getb"); break;
|
||||
case16(0xf0): sprintf(t, "iwt r%u,#$%.2x%.2x", op0 & 15, op2 & 255, op1 & 255); break;
|
||||
}
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
auto GSU::disassembleALT1(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
case (0x01): sprintf(t, "nop"); break;
|
||||
case (0x02): sprintf(t, "cache"); break;
|
||||
case (0x03): sprintf(t, "lsr"); break;
|
||||
case (0x04): sprintf(t, "rol"); break;
|
||||
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
|
||||
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
|
||||
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
|
||||
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
|
||||
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
|
||||
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
|
||||
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
|
||||
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
|
||||
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
|
||||
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
|
||||
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
|
||||
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
|
||||
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
|
||||
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
|
||||
case (0x3c): sprintf(t, "loop"); break;
|
||||
case (0x3d): sprintf(t, "alt1"); break;
|
||||
case (0x3e): sprintf(t, "alt2"); break;
|
||||
case (0x3f): sprintf(t, "alt3"); break;
|
||||
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
|
||||
case (0x4c): sprintf(t, "rpix"); break;
|
||||
case (0x4d): sprintf(t, "swap"); break;
|
||||
case (0x4e): sprintf(t, "cmode"); break;
|
||||
case (0x4f): sprintf(t, "not"); break;
|
||||
case16(0x50): sprintf(t, "adc r%u", op0 & 15); break;
|
||||
case16(0x60): sprintf(t, "sbc r%u", op0 & 15); break;
|
||||
case (0x70): sprintf(t, "merge"); break;
|
||||
case15(0x71): sprintf(t, "bic r%u", op0 & 15); break;
|
||||
case16(0x80): sprintf(t, "umult r%u", op0 & 15); break;
|
||||
case (0x90): sprintf(t, "sbk"); break;
|
||||
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
|
||||
case (0x95): sprintf(t, "sex"); break;
|
||||
case (0x96): sprintf(t, "div2"); break;
|
||||
case (0x97): sprintf(t, "ror"); break;
|
||||
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
|
||||
case (0x9e): sprintf(t, "lob"); break;
|
||||
case (0x9f): sprintf(t, "lmult"); break;
|
||||
case16(0xa0): sprintf(t, "lms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
|
||||
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
|
||||
case (0xc0): sprintf(t, "hib"); break;
|
||||
case15(0xc1): sprintf(t, "xor r%u", op0 & 15); break;
|
||||
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
|
||||
case (0xdf): sprintf(t, "getc"); break;
|
||||
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
|
||||
case (0xef): sprintf(t, "getbh"); break;
|
||||
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
|
||||
}
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
auto GSU::disassembleALT2(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
case (0x01): sprintf(t, "nop"); break;
|
||||
case (0x02): sprintf(t, "cache"); break;
|
||||
case (0x03): sprintf(t, "lsr"); break;
|
||||
case (0x04): sprintf(t, "rol"); break;
|
||||
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
|
||||
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
|
||||
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
|
||||
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
|
||||
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
|
||||
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
|
||||
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
|
||||
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
|
||||
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
|
||||
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
|
||||
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
|
||||
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
|
||||
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
|
||||
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
|
||||
case (0x3c): sprintf(t, "loop"); break;
|
||||
case (0x3d): sprintf(t, "alt1"); break;
|
||||
case (0x3e): sprintf(t, "alt2"); break;
|
||||
case (0x3f): sprintf(t, "alt3"); break;
|
||||
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
|
||||
case (0x4c): sprintf(t, "plot"); break;
|
||||
case (0x4d): sprintf(t, "swap"); break;
|
||||
case (0x4e): sprintf(t, "color"); break;
|
||||
case (0x4f): sprintf(t, "not"); break;
|
||||
case16(0x50): sprintf(t, "add #%u", op0 & 15); break;
|
||||
case16(0x60): sprintf(t, "sub #%u", op0 & 15); break;
|
||||
case (0x70): sprintf(t, "merge"); break;
|
||||
case15(0x71): sprintf(t, "and #%u", op0 & 15); break;
|
||||
case16(0x80): sprintf(t, "mult #%u", op0 & 15); break;
|
||||
case (0x90): sprintf(t, "sbk"); break;
|
||||
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
|
||||
case (0x95): sprintf(t, "sex"); break;
|
||||
case (0x96): sprintf(t, "asr"); break;
|
||||
case (0x97): sprintf(t, "ror"); break;
|
||||
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
|
||||
case (0x9e): sprintf(t, "lob"); break;
|
||||
case (0x9f): sprintf(t, "fmult"); break;
|
||||
case16(0xa0): sprintf(t, "sms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
|
||||
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
|
||||
case (0xc0): sprintf(t, "hib"); break;
|
||||
case15(0xc1): sprintf(t, "or #%u", op0 & 15); break;
|
||||
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
|
||||
case (0xdf): sprintf(t, "ramb"); break;
|
||||
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
|
||||
case (0xef): sprintf(t, "getbl"); break;
|
||||
case16(0xf0): sprintf(t, "sm r%u", op0 & 15); break;
|
||||
}
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
auto GSU::disassembleALT3(char* output) -> void {
|
||||
char t[256] = "";
|
||||
switch(op0) {
|
||||
case (0x00): sprintf(t, "stop"); break;
|
||||
case (0x01): sprintf(t, "nop"); break;
|
||||
case (0x02): sprintf(t, "cache"); break;
|
||||
case (0x03): sprintf(t, "lsr"); break;
|
||||
case (0x04): sprintf(t, "rol"); break;
|
||||
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
|
||||
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
|
||||
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
|
||||
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
|
||||
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
|
||||
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
|
||||
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
|
||||
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
|
||||
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
|
||||
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
|
||||
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
|
||||
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
|
||||
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
|
||||
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
|
||||
case (0x3c): sprintf(t, "loop"); break;
|
||||
case (0x3d): sprintf(t, "alt1"); break;
|
||||
case (0x3e): sprintf(t, "alt2"); break;
|
||||
case (0x3f): sprintf(t, "alt3"); break;
|
||||
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
|
||||
case (0x4c): sprintf(t, "rpix"); break;
|
||||
case (0x4d): sprintf(t, "swap"); break;
|
||||
case (0x4e): sprintf(t, "cmode"); break;
|
||||
case (0x4f): sprintf(t, "not"); break;
|
||||
case16(0x50): sprintf(t, "adc #%u", op0 & 15); break;
|
||||
case16(0x60): sprintf(t, "cmp r%u", op0 & 15); break;
|
||||
case (0x70): sprintf(t, "merge"); break;
|
||||
case15(0x71): sprintf(t, "bic #%u", op0 & 15); break;
|
||||
case16(0x80): sprintf(t, "umult #%u", op0 & 15); break;
|
||||
case (0x90): sprintf(t, "sbk"); break;
|
||||
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
|
||||
case (0x95): sprintf(t, "sex"); break;
|
||||
case (0x96): sprintf(t, "div2"); break;
|
||||
case (0x97): sprintf(t, "ror"); break;
|
||||
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
|
||||
case (0x9e): sprintf(t, "lob"); break;
|
||||
case (0x9f): sprintf(t, "lmult"); break;
|
||||
case16(0xa0): sprintf(t, "lms r%u", op0 & 15); break;
|
||||
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
|
||||
case (0xc0): sprintf(t, "hib"); break;
|
||||
case15(0xc1): sprintf(t, "xor #%u", op0 & 15); break;
|
||||
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
|
||||
case (0xdf): sprintf(t, "romb"); break;
|
||||
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
|
||||
case (0xef): sprintf(t, "getbs"); break;
|
||||
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
|
||||
}
|
||||
strcat(output, t);
|
||||
}
|
||||
|
||||
#undef case4
|
||||
#undef case6
|
||||
#undef case12
|
||||
#undef case15
|
||||
#undef case16
|
||||
#undef op0
|
||||
#undef op1
|
||||
#undef op2
|
||||
@@ -1,39 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "gsu.hpp"
|
||||
|
||||
//note: multiplication results *may* sometimes be invalid when both CLSR and MS0 are set
|
||||
//the product of multiplication in this mode (21mhz + fast-multiply) has not been analyzed;
|
||||
//however, the timing of this mode has been confirmed to work as specified below
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
auto GSU::power() -> void {
|
||||
for(auto& r : regs.r) {
|
||||
r.data = 0x0000;
|
||||
r.modified = false;
|
||||
}
|
||||
|
||||
regs.sfr = 0x0000;
|
||||
regs.pbr = 0x00;
|
||||
regs.rombr = 0x00;
|
||||
regs.rambr = 0;
|
||||
regs.cbr = 0x0000;
|
||||
regs.scbr = 0x00;
|
||||
regs.scmr = 0x00;
|
||||
regs.colr = 0x00;
|
||||
regs.por = 0x00;
|
||||
regs.bramr = 0;
|
||||
regs.vcr = 0x04;
|
||||
regs.cfgr = 0x00;
|
||||
regs.clsr = 0;
|
||||
regs.pipeline = 0x01; //nop
|
||||
regs.ramaddr = 0x0000;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
struct GSU {
|
||||
#include "registers.hpp"
|
||||
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
|
||||
virtual auto stop() -> void = 0;
|
||||
virtual auto color(uint8 source) -> uint8 = 0;
|
||||
virtual auto plot(uint8 x, uint8 y) -> void = 0;
|
||||
virtual auto rpix(uint8 x, uint8 y) -> uint8 = 0;
|
||||
|
||||
virtual auto pipe() -> uint8 = 0;
|
||||
virtual auto syncROMBuffer() -> void = 0;
|
||||
virtual auto readROMBuffer() -> uint8 = 0;
|
||||
virtual auto syncRAMBuffer() -> void = 0;
|
||||
virtual auto readRAMBuffer(uint16 address) -> uint8 = 0;
|
||||
virtual auto writeRAMBuffer(uint16 address, uint8 data) -> void = 0;
|
||||
virtual auto flushCache() -> void = 0;
|
||||
|
||||
virtual auto read(uint24 address, uint8 data = 0x00) -> uint8 = 0;
|
||||
virtual auto write(uint24 address, uint8 data) -> void = 0;
|
||||
|
||||
//gsu.cpp
|
||||
auto power() -> void;
|
||||
|
||||
//instructions.cpp
|
||||
auto instructionADD_ADC(uint n) -> void;
|
||||
auto instructionALT1() -> void;
|
||||
auto instructionALT2() -> void;
|
||||
auto instructionALT3() -> void;
|
||||
auto instructionAND_BIC(uint n) -> void;
|
||||
auto instructionASR_DIV2() -> void;
|
||||
auto instructionBranch(bool c) -> void;
|
||||
auto instructionCACHE() -> void;
|
||||
auto instructionCOLOR_CMODE() -> void;
|
||||
auto instructionDEC(uint n) -> void;
|
||||
auto instructionFMULT_LMULT() -> void;
|
||||
auto instructionFROM_MOVES(uint n) -> void;
|
||||
auto instructionGETB() -> void;
|
||||
auto instructionGETC_RAMB_ROMB() -> void;
|
||||
auto instructionHIB() -> void;
|
||||
auto instructionIBT_LMS_SMS(uint n) -> void;
|
||||
auto instructionINC(uint n) -> void;
|
||||
auto instructionIWT_LM_SM(uint n) -> void;
|
||||
auto instructionJMP_LJMP(uint n) -> void;
|
||||
auto instructionLINK(uint n) -> void;
|
||||
auto instructionLoad(uint n) -> void;
|
||||
auto instructionLOB() -> void;
|
||||
auto instructionLOOP() -> void;
|
||||
auto instructionLSR() -> void;
|
||||
auto instructionMERGE() -> void;
|
||||
auto instructionMULT_UMULT(uint n) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
auto instructionNOT() -> void;
|
||||
auto instructionOR_XOR(uint n) -> void;
|
||||
auto instructionPLOT_RPIX() -> void;
|
||||
auto instructionROL() -> void;
|
||||
auto instructionROR() -> void;
|
||||
auto instructionSBK() -> void;
|
||||
auto instructionSEX() -> void;
|
||||
auto instructionStore(uint n) -> void;
|
||||
auto instructionSTOP() -> void;
|
||||
auto instructionSUB_SBC_CMP(uint n) -> void;
|
||||
auto instructionSWAP() -> void;
|
||||
auto instructionTO_MOVE(uint n) -> void;
|
||||
auto instructionWITH(uint n) -> void;
|
||||
|
||||
//switch.cpp
|
||||
auto instruction(uint8 opcode) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
noinline auto disassembleInstruction() -> string;
|
||||
noinline auto disassembleContext() -> string;
|
||||
|
||||
auto disassembleOpcode(char* output) -> void;
|
||||
auto disassembleALT0(char* output) -> void;
|
||||
auto disassembleALT1(char* output) -> void;
|
||||
auto disassembleALT2(char* output) -> void;
|
||||
auto disassembleALT3(char* output) -> void;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
auto GSU::instruction(uint8 opcode) -> void {
|
||||
#define op(id, name, ...) \
|
||||
case id: return instruction##name(__VA_ARGS__); \
|
||||
|
||||
#define op4(id, name) \
|
||||
case id+ 0: return instruction##name((uint4)opcode); \
|
||||
case id+ 1: return instruction##name((uint4)opcode); \
|
||||
case id+ 2: return instruction##name((uint4)opcode); \
|
||||
case id+ 3: return instruction##name((uint4)opcode); \
|
||||
|
||||
#define op6(id, name) \
|
||||
op4(id, name) \
|
||||
case id+ 4: return instruction##name((uint4)opcode); \
|
||||
case id+ 5: return instruction##name((uint4)opcode); \
|
||||
|
||||
#define op12(id, name) \
|
||||
op6(id, name) \
|
||||
case id+ 6: return instruction##name((uint4)opcode); \
|
||||
case id+ 7: return instruction##name((uint4)opcode); \
|
||||
case id+ 8: return instruction##name((uint4)opcode); \
|
||||
case id+ 9: return instruction##name((uint4)opcode); \
|
||||
case id+10: return instruction##name((uint4)opcode); \
|
||||
case id+11: return instruction##name((uint4)opcode); \
|
||||
|
||||
#define op15(id, name) \
|
||||
op12(id, name) \
|
||||
case id+12: return instruction##name((uint4)opcode); \
|
||||
case id+13: return instruction##name((uint4)opcode); \
|
||||
case id+14: return instruction##name((uint4)opcode); \
|
||||
|
||||
#define op16(id, name) \
|
||||
op15(id, name) \
|
||||
case id+15: return instruction##name((uint4)opcode); \
|
||||
|
||||
switch(opcode) {
|
||||
op (0x00, STOP)
|
||||
op (0x01, NOP)
|
||||
op (0x02, CACHE)
|
||||
op (0x03, LSR)
|
||||
op (0x04, ROL)
|
||||
op (0x05, Branch, 1) //bra
|
||||
op (0x06, Branch, (regs.sfr.s ^ regs.sfr.ov) == 0) //blt
|
||||
op (0x07, Branch, (regs.sfr.s ^ regs.sfr.ov) == 1) //bge
|
||||
op (0x08, Branch, regs.sfr.z == 0) //bne
|
||||
op (0x09, Branch, regs.sfr.z == 1) //beq
|
||||
op (0x0a, Branch, regs.sfr.s == 0) //bpl
|
||||
op (0x0b, Branch, regs.sfr.s == 1) //bmi
|
||||
op (0x0c, Branch, regs.sfr.cy == 0) //bcc
|
||||
op (0x0d, Branch, regs.sfr.cy == 1) //bcs
|
||||
op (0x0e, Branch, regs.sfr.ov == 0) //bvc
|
||||
op (0x0f, Branch, regs.sfr.ov == 1) //bvs
|
||||
op16(0x10, TO_MOVE)
|
||||
op16(0x20, WITH)
|
||||
op12(0x30, Store)
|
||||
op (0x3c, LOOP)
|
||||
op (0x3d, ALT1)
|
||||
op (0x3e, ALT2)
|
||||
op (0x3f, ALT3)
|
||||
op12(0x40, Load)
|
||||
op (0x4c, PLOT_RPIX)
|
||||
op (0x4d, SWAP)
|
||||
op (0x4e, COLOR_CMODE)
|
||||
op (0x4f, NOT)
|
||||
op16(0x50, ADD_ADC)
|
||||
op16(0x60, SUB_SBC_CMP)
|
||||
op (0x70, MERGE)
|
||||
op15(0x71, AND_BIC)
|
||||
op16(0x80, MULT_UMULT)
|
||||
op (0x90, SBK)
|
||||
op4 (0x91, LINK)
|
||||
op (0x95, SEX)
|
||||
op (0x96, ASR_DIV2)
|
||||
op (0x97, ROR)
|
||||
op6 (0x98, JMP_LJMP)
|
||||
op (0x9e, LOB)
|
||||
op (0x9f, FMULT_LMULT)
|
||||
op16(0xa0, IBT_LMS_SMS)
|
||||
op16(0xb0, FROM_MOVES)
|
||||
op (0xc0, HIB)
|
||||
op15(0xc1, OR_XOR)
|
||||
op15(0xd0, INC)
|
||||
op (0xdf, GETC_RAMB_ROMB)
|
||||
op15(0xe0, DEC)
|
||||
op (0xef, GETB)
|
||||
op16(0xf0, IWT_LM_SM)
|
||||
}
|
||||
|
||||
#undef op
|
||||
#undef op4
|
||||
#undef op6
|
||||
#undef op12
|
||||
#undef op15
|
||||
#undef op16
|
||||
}
|
||||
@@ -1,424 +0,0 @@
|
||||
//$00 stop
|
||||
auto GSU::instructionSTOP() -> void {
|
||||
if(regs.cfgr.irq == 0) {
|
||||
regs.sfr.irq = 1;
|
||||
stop();
|
||||
}
|
||||
regs.sfr.g = 0;
|
||||
regs.pipeline = 0x01; //nop
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$01 nop
|
||||
auto GSU::instructionNOP() -> void {
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$02 cache
|
||||
auto GSU::instructionCACHE() -> void {
|
||||
if(regs.cbr != (regs.r[15] & 0xfff0)) {
|
||||
regs.cbr = regs.r[15] & 0xfff0;
|
||||
flushCache();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$03 lsr
|
||||
auto GSU::instructionLSR() -> void {
|
||||
regs.sfr.cy = (regs.sr() & 1);
|
||||
regs.dr() = regs.sr() >> 1;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$04 rol
|
||||
auto GSU::instructionROL() -> void {
|
||||
bool carry = (regs.sr() & 0x8000);
|
||||
regs.dr() = (regs.sr() << 1) | regs.sfr.cy;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.cy = carry;
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$05 bra e
|
||||
//$06 blt e
|
||||
//$07 bge e
|
||||
//$08 bne e
|
||||
//$09 beq e
|
||||
//$0a bpl e
|
||||
//$0b bmi e
|
||||
//$0c bcc e
|
||||
//$0d bcs e
|
||||
//$0e bvc e
|
||||
//$0f bvs e
|
||||
auto GSU::instructionBranch(bool take) -> void {
|
||||
auto displacement = (int8)pipe();
|
||||
if(take) regs.r[15] += displacement;
|
||||
}
|
||||
|
||||
//$10-1f(b0) to rN
|
||||
//$10-1f(b1) move rN
|
||||
auto GSU::instructionTO_MOVE(uint n) -> void {
|
||||
if(!regs.sfr.b) {
|
||||
regs.dreg = n;
|
||||
} else {
|
||||
regs.r[n] = regs.sr();
|
||||
regs.reset();
|
||||
}
|
||||
}
|
||||
|
||||
//$20-2f with rN
|
||||
auto GSU::instructionWITH(uint n) -> void {
|
||||
regs.sreg = n;
|
||||
regs.dreg = n;
|
||||
regs.sfr.b = 1;
|
||||
}
|
||||
|
||||
//$30-3b(alt0) stw (rN)
|
||||
//$30-3b(alt1) stb (rN)
|
||||
auto GSU::instructionStore(uint n) -> void {
|
||||
regs.ramaddr = regs.r[n];
|
||||
writeRAMBuffer(regs.ramaddr, regs.sr());
|
||||
if(!regs.sfr.alt1) writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$3c loop
|
||||
auto GSU::instructionLOOP() -> void {
|
||||
regs.r[12]--;
|
||||
regs.sfr.s = (regs.r[12] & 0x8000);
|
||||
regs.sfr.z = (regs.r[12] == 0);
|
||||
if(!regs.sfr.z) regs.r[15] = regs.r[13];
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$3d alt1
|
||||
auto GSU::instructionALT1() -> void {
|
||||
regs.sfr.b = 0;
|
||||
regs.sfr.alt1 = 1;
|
||||
}
|
||||
|
||||
//$3e alt2
|
||||
auto GSU::instructionALT2() -> void {
|
||||
regs.sfr.b = 0;
|
||||
regs.sfr.alt2 = 1;
|
||||
}
|
||||
|
||||
//$3f alt3
|
||||
auto GSU::instructionALT3() -> void {
|
||||
regs.sfr.b = 0;
|
||||
regs.sfr.alt1 = 1;
|
||||
regs.sfr.alt2 = 1;
|
||||
}
|
||||
|
||||
//$40-4b(alt0) ldw (rN)
|
||||
//$40-4b(alt1) ldb (rN)
|
||||
auto GSU::instructionLoad(uint n) -> void {
|
||||
regs.ramaddr = regs.r[n];
|
||||
regs.dr() = readRAMBuffer(regs.ramaddr);
|
||||
if(!regs.sfr.alt1) regs.dr() |= readRAMBuffer(regs.ramaddr ^ 1) << 8;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4c(alt0) plot
|
||||
//$4c(alt1) rpix
|
||||
auto GSU::instructionPLOT_RPIX() -> void {
|
||||
if(!regs.sfr.alt1) {
|
||||
plot(regs.r[1], regs.r[2]);
|
||||
regs.r[1]++;
|
||||
} else {
|
||||
regs.dr() = rpix(regs.r[1], regs.r[2]);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4d swap
|
||||
auto GSU::instructionSWAP() -> void {
|
||||
regs.dr() = regs.sr() >> 8 | regs.sr() << 8;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4e(alt0) color
|
||||
//$4e(alt1) cmode
|
||||
auto GSU::instructionCOLOR_CMODE() -> void {
|
||||
if(!regs.sfr.alt1) {
|
||||
regs.colr = color(regs.sr());
|
||||
} else {
|
||||
regs.por = regs.sr();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$4f not
|
||||
auto GSU::instructionNOT() -> void {
|
||||
regs.dr() = ~regs.sr();
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$50-5f(alt0) add rN
|
||||
//$50-5f(alt1) adc rN
|
||||
//$50-5f(alt2) add #N
|
||||
//$50-5f(alt3) adc #N
|
||||
auto GSU::instructionADD_ADC(uint n) -> void {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
int r = regs.sr() + n + (regs.sfr.alt1 ? regs.sfr.cy : 0);
|
||||
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0x10000);
|
||||
regs.sfr.z = ((uint16)r == 0);
|
||||
regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$60-6f(alt0) sub rN
|
||||
//$60-6f(alt1) sbc rN
|
||||
//$60-6f(alt2) sub #N
|
||||
//$60-6f(alt3) cmp rN
|
||||
auto GSU::instructionSUB_SBC_CMP(uint n) -> void {
|
||||
if(!regs.sfr.alt2 || regs.sfr.alt1) n = regs.r[n];
|
||||
int r = regs.sr() - n - (!regs.sfr.alt2 && regs.sfr.alt1 ? !regs.sfr.cy : 0);
|
||||
regs.sfr.ov = (regs.sr() ^ n) & (regs.sr() ^ r) & 0x8000;
|
||||
regs.sfr.s = (r & 0x8000);
|
||||
regs.sfr.cy = (r >= 0);
|
||||
regs.sfr.z = ((uint16)r == 0);
|
||||
if(!regs.sfr.alt2 || !regs.sfr.alt1) regs.dr() = r;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$70 merge
|
||||
auto GSU::instructionMERGE() -> void {
|
||||
regs.dr() = (regs.r[7] & 0xff00) | (regs.r[8] >> 8);
|
||||
regs.sfr.ov = (regs.dr() & 0xc0c0);
|
||||
regs.sfr.s = (regs.dr() & 0x8080);
|
||||
regs.sfr.cy = (regs.dr() & 0xe0e0);
|
||||
regs.sfr.z = (regs.dr() & 0xf0f0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$71-7f(alt0) and rN
|
||||
//$71-7f(alt1) bic rN
|
||||
//$71-7f(alt2) and #N
|
||||
//$71-7f(alt3) bic #N
|
||||
auto GSU::instructionAND_BIC(uint n) -> void {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
regs.dr() = regs.sr() & (regs.sfr.alt1 ? ~n : n);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$80-8f(alt0) mult rN
|
||||
//$80-8f(alt1) umult rN
|
||||
//$80-8f(alt2) mult #N
|
||||
//$80-8f(alt3) umult #N
|
||||
auto GSU::instructionMULT_UMULT(uint n) -> void {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
regs.dr() = (!regs.sfr.alt1 ? uint16((int8)regs.sr() * (int8)n) : uint16((uint8)regs.sr() * (uint8)n));
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||
}
|
||||
|
||||
//$90 sbk
|
||||
auto GSU::instructionSBK() -> void {
|
||||
writeRAMBuffer(regs.ramaddr ^ 0, regs.sr() >> 0);
|
||||
writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$91-94 link #N
|
||||
auto GSU::instructionLINK(uint n) -> void {
|
||||
regs.r[11] = regs.r[15] + n;
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$95 sex
|
||||
auto GSU::instructionSEX() -> void {
|
||||
regs.dr() = (int8)regs.sr();
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$96(alt0) asr
|
||||
//$96(alt1) div2
|
||||
auto GSU::instructionASR_DIV2() -> void {
|
||||
regs.sfr.cy = (regs.sr() & 1);
|
||||
regs.dr() = ((int16)regs.sr() >> 1) + (regs.sfr.alt1 ? ((regs.sr() + 1) >> 16) : 0);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$97 ror
|
||||
auto GSU::instructionROR() -> void {
|
||||
bool carry = (regs.sr() & 1);
|
||||
regs.dr() = (regs.sfr.cy << 15) | (regs.sr() >> 1);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.cy = carry;
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$98-9d(alt0) jmp rN
|
||||
//$98-9d(alt1) ljmp rN
|
||||
auto GSU::instructionJMP_LJMP(uint n) -> void {
|
||||
if(!regs.sfr.alt1) {
|
||||
regs.r[15] = regs.r[n];
|
||||
} else {
|
||||
regs.pbr = regs.r[n] & 0x7f;
|
||||
regs.r[15] = regs.sr();
|
||||
regs.cbr = regs.r[15] & 0xfff0;
|
||||
flushCache();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$9e lob
|
||||
auto GSU::instructionLOB() -> void {
|
||||
regs.dr() = regs.sr() & 0xff;
|
||||
regs.sfr.s = (regs.dr() & 0x80);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$9f(alt0) fmult
|
||||
//$9f(alt1) lmult
|
||||
auto GSU::instructionFMULT_LMULT() -> void {
|
||||
uint32 result = (int16)regs.sr() * (int16)regs.r[6];
|
||||
if(regs.sfr.alt1) regs.r[4] = result;
|
||||
regs.dr() = result >> 16;
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.cy = (result & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
step((regs.cfgr.ms0 ? 3 : 7) * (regs.clsr ? 1 : 2));
|
||||
}
|
||||
|
||||
//$a0-af(alt0) ibt rN,#pp
|
||||
//$a0-af(alt1) lms rN,(yy)
|
||||
//$a0-af(alt2) sms (yy),rN
|
||||
auto GSU::instructionIBT_LMS_SMS(uint n) -> void {
|
||||
if(regs.sfr.alt1) {
|
||||
regs.ramaddr = pipe() << 1;
|
||||
uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0;
|
||||
regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo;
|
||||
} else if(regs.sfr.alt2) {
|
||||
regs.ramaddr = pipe() << 1;
|
||||
writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0);
|
||||
writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8);
|
||||
} else {
|
||||
regs.r[n] = (int8)pipe();
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$b0-bf(b0) from rN
|
||||
//$b0-bf(b1) moves rN
|
||||
auto GSU::instructionFROM_MOVES(uint n) -> void {
|
||||
if(!regs.sfr.b) {
|
||||
regs.sreg = n;
|
||||
} else {
|
||||
regs.dr() = regs.r[n];
|
||||
regs.sfr.ov = (regs.dr() & 0x80);
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
}
|
||||
|
||||
//$c0 hib
|
||||
auto GSU::instructionHIB() -> void {
|
||||
regs.dr() = regs.sr() >> 8;
|
||||
regs.sfr.s = (regs.dr() & 0x80);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$c1-cf(alt0) or rN
|
||||
//$c1-cf(alt1) xor rN
|
||||
//$c1-cf(alt2) or #N
|
||||
//$c1-cf(alt3) xor #N
|
||||
auto GSU::instructionOR_XOR(uint n) -> void {
|
||||
if(!regs.sfr.alt2) n = regs.r[n];
|
||||
regs.dr() = (!regs.sfr.alt1 ? (regs.sr() | n) : (regs.sr() ^ n));
|
||||
regs.sfr.s = (regs.dr() & 0x8000);
|
||||
regs.sfr.z = (regs.dr() == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$d0-de inc rN
|
||||
auto GSU::instructionINC(uint n) -> void {
|
||||
regs.r[n]++;
|
||||
regs.sfr.s = (regs.r[n] & 0x8000);
|
||||
regs.sfr.z = (regs.r[n] == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$df(alt0) getc
|
||||
//$df(alt2) ramb
|
||||
//$df(alt3) romb
|
||||
auto GSU::instructionGETC_RAMB_ROMB() -> void {
|
||||
if(!regs.sfr.alt2) {
|
||||
regs.colr = color(readROMBuffer());
|
||||
} else if(!regs.sfr.alt1) {
|
||||
syncRAMBuffer();
|
||||
regs.rambr = regs.sr() & 0x01;
|
||||
} else {
|
||||
syncROMBuffer();
|
||||
regs.rombr = regs.sr() & 0x7f;
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$e0-ee dec rN
|
||||
auto GSU::instructionDEC(uint n) -> void {
|
||||
regs.r[n]--;
|
||||
regs.sfr.s = (regs.r[n] & 0x8000);
|
||||
regs.sfr.z = (regs.r[n] == 0);
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$ef(alt0) getb
|
||||
//$ef(alt1) getbh
|
||||
//$ef(alt2) getbl
|
||||
//$ef(alt3) getbs
|
||||
auto GSU::instructionGETB() -> void {
|
||||
switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) {
|
||||
case 0: regs.dr() = readROMBuffer(); break;
|
||||
case 1: regs.dr() = readROMBuffer() << 8 | (uint8)regs.sr(); break;
|
||||
case 2: regs.dr() = (regs.sr() & 0xff00) | readROMBuffer(); break;
|
||||
case 3: regs.dr() = (int8)readROMBuffer(); break;
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
|
||||
//$f0-ff(alt0) iwt rN,#xx
|
||||
//$f0-ff(alt1) lm rN,(xx)
|
||||
//$f0-ff(alt2) sm (xx),rN
|
||||
auto GSU::instructionIWT_LM_SM(uint n) -> void {
|
||||
if(regs.sfr.alt1) {
|
||||
regs.ramaddr = pipe() << 0;
|
||||
regs.ramaddr |= pipe() << 8;
|
||||
uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0;
|
||||
regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo;
|
||||
} else if(regs.sfr.alt2) {
|
||||
regs.ramaddr = pipe() << 0;
|
||||
regs.ramaddr |= pipe() << 8;
|
||||
writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0);
|
||||
writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8);
|
||||
} else {
|
||||
uint8 lo = pipe();
|
||||
regs.r[n] = pipe() << 8 | lo;
|
||||
}
|
||||
regs.reset();
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
struct Register {
|
||||
uint16 data = 0;
|
||||
bool modified = false;
|
||||
|
||||
inline operator uint() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
inline auto assign(uint value) -> uint16 {
|
||||
modified = true;
|
||||
return data = value;
|
||||
}
|
||||
|
||||
inline auto operator++() { return assign(data + 1); }
|
||||
inline auto operator--() { return assign(data - 1); }
|
||||
inline auto operator++(int) { uint r = data; assign(data + 1); return r; }
|
||||
inline auto operator--(int) { uint r = data; assign(data - 1); return r; }
|
||||
inline auto operator = (uint i) { return assign(i); }
|
||||
inline auto operator |= (uint i) { return assign(data | i); }
|
||||
inline auto operator ^= (uint i) { return assign(data ^ i); }
|
||||
inline auto operator &= (uint i) { return assign(data & i); }
|
||||
inline auto operator <<= (uint i) { return assign(data << i); }
|
||||
inline auto operator >>= (uint i) { return assign(data >> i); }
|
||||
inline auto operator += (uint i) { return assign(data + i); }
|
||||
inline auto operator -= (uint i) { return assign(data - i); }
|
||||
inline auto operator *= (uint i) { return assign(data * i); }
|
||||
inline auto operator /= (uint i) { return assign(data / i); }
|
||||
inline auto operator %= (uint i) { return assign(data % i); }
|
||||
|
||||
inline auto operator = (const Register& value) { return assign(value); }
|
||||
|
||||
Register() = default;
|
||||
Register(const Register&) = delete;
|
||||
};
|
||||
|
||||
struct SFR {
|
||||
uint16 data;
|
||||
BitField<16, 1> z {&data}; //zero flag
|
||||
BitField<16, 2> cy {&data}; //carry flag
|
||||
BitField<16, 3> s {&data}; //sign flag
|
||||
BitField<16, 4> ov {&data}; //overflow flag
|
||||
BitField<16, 5> g {&data}; //go flag
|
||||
BitField<16, 6> r {&data}; //ROM r14 flag
|
||||
BitField<16, 8> alt1{&data}; //alt1 instruction mode
|
||||
BitField<16, 9> alt2{&data}; //alt2 instruction mode
|
||||
BitField<16,10> il {&data}; //immediate lower 8-bit flag
|
||||
BitField<16,11> ih {&data}; //immediate upper 8-bit flag
|
||||
BitField<16,12> b {&data}; //with flag
|
||||
BitField<16,15> irq {&data}; //interrupt flag
|
||||
|
||||
BitRange<16,8,9> alt{&data}; //composite instruction mode
|
||||
|
||||
SFR() = default;
|
||||
SFR(const SFR&) = delete;
|
||||
auto operator=(const SFR&) = delete;
|
||||
|
||||
inline operator uint() const { return data & 0x9f7e; }
|
||||
inline auto& operator=(const uint value) { return data = value, *this; }
|
||||
};
|
||||
|
||||
struct SCMR {
|
||||
uint ht;
|
||||
bool ron;
|
||||
bool ran;
|
||||
uint md;
|
||||
|
||||
operator uint() const {
|
||||
return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md);
|
||||
}
|
||||
|
||||
auto& operator=(uint data) {
|
||||
ht = (bool)(data & 0x20) << 1;
|
||||
ht |= (bool)(data & 0x04) << 0;
|
||||
ron = data & 0x10;
|
||||
ran = data & 0x08;
|
||||
md = data & 0x03;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct POR {
|
||||
bool obj;
|
||||
bool freezehigh;
|
||||
bool highnibble;
|
||||
bool dither;
|
||||
bool transparent;
|
||||
|
||||
operator uint() const {
|
||||
return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent);
|
||||
}
|
||||
|
||||
auto& operator=(uint data) {
|
||||
obj = data & 0x10;
|
||||
freezehigh = data & 0x08;
|
||||
highnibble = data & 0x04;
|
||||
dither = data & 0x02;
|
||||
transparent = data & 0x01;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct CFGR {
|
||||
bool irq;
|
||||
bool ms0;
|
||||
|
||||
operator uint() const {
|
||||
return (irq << 7) | (ms0 << 5);
|
||||
}
|
||||
|
||||
auto& operator=(uint data) {
|
||||
irq = data & 0x80;
|
||||
ms0 = data & 0x20;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
uint8 pipeline;
|
||||
uint16 ramaddr;
|
||||
|
||||
Register r[16]; //general purpose registers
|
||||
SFR sfr; //status flag register
|
||||
uint8 pbr; //program bank register
|
||||
uint8 rombr; //game pack ROM bank register
|
||||
bool rambr; //game pack RAM bank register
|
||||
uint16 cbr; //cache base register
|
||||
uint8 scbr; //screen base register
|
||||
SCMR scmr; //screen mode register
|
||||
uint8 colr; //color register
|
||||
POR por; //plot option register
|
||||
bool bramr; //back-up RAM register
|
||||
uint8 vcr; //version code register
|
||||
CFGR cfgr; //config register
|
||||
bool clsr; //clock select register
|
||||
|
||||
uint romcl; //clock ticks until romdr is valid
|
||||
uint8 romdr; //ROM buffer data register
|
||||
|
||||
uint ramcl; //clock ticks until ramdr is valid
|
||||
uint16 ramar; //RAM buffer address register
|
||||
uint8 ramdr; //RAM buffer data register
|
||||
|
||||
uint sreg;
|
||||
uint dreg;
|
||||
auto& sr() { return r[sreg]; } //source register (from)
|
||||
auto& dr() { return r[dreg]; } //destination register (to)
|
||||
|
||||
auto reset() -> void {
|
||||
sfr.b = 0;
|
||||
sfr.alt1 = 0;
|
||||
sfr.alt2 = 0;
|
||||
|
||||
sreg = 0;
|
||||
dreg = 0;
|
||||
}
|
||||
} regs;
|
||||
|
||||
struct Cache {
|
||||
uint8 buffer[512];
|
||||
bool valid[32];
|
||||
} cache;
|
||||
|
||||
struct PixelCache {
|
||||
uint16 offset;
|
||||
uint8 bitpend;
|
||||
uint8 data[8];
|
||||
} pixelcache[2];
|
||||
@@ -1,56 +0,0 @@
|
||||
auto GSU::serialize(serializer& s) -> void {
|
||||
s.integer(regs.pipeline);
|
||||
s.integer(regs.ramaddr);
|
||||
|
||||
for(auto n : range(16)) {
|
||||
s.integer(regs.r[n].data);
|
||||
s.integer(regs.r[n].modified);
|
||||
}
|
||||
|
||||
s.integer(regs.sfr.data);
|
||||
s.integer(regs.pbr);
|
||||
s.integer(regs.rombr);
|
||||
s.integer(regs.rambr);
|
||||
s.integer(regs.cbr);
|
||||
s.integer(regs.scbr);
|
||||
|
||||
s.integer(regs.scmr.ht);
|
||||
s.integer(regs.scmr.ron);
|
||||
s.integer(regs.scmr.ran);
|
||||
s.integer(regs.scmr.md);
|
||||
|
||||
s.integer(regs.colr);
|
||||
|
||||
s.integer(regs.por.obj);
|
||||
s.integer(regs.por.freezehigh);
|
||||
s.integer(regs.por.highnibble);
|
||||
s.integer(regs.por.dither);
|
||||
s.integer(regs.por.transparent);
|
||||
|
||||
s.integer(regs.bramr);
|
||||
s.integer(regs.vcr);
|
||||
|
||||
s.integer(regs.cfgr.irq);
|
||||
s.integer(regs.cfgr.ms0);
|
||||
|
||||
s.integer(regs.clsr);
|
||||
|
||||
s.integer(regs.romcl);
|
||||
s.integer(regs.romdr);
|
||||
|
||||
s.integer(regs.ramcl);
|
||||
s.integer(regs.ramar);
|
||||
s.integer(regs.ramdr);
|
||||
|
||||
s.integer(regs.sreg);
|
||||
s.integer(regs.dreg);
|
||||
|
||||
s.array(cache.buffer);
|
||||
s.array(cache.valid);
|
||||
|
||||
for(uint n : range(2)) {
|
||||
s.integer(pixelcache[n].offset);
|
||||
s.integer(pixelcache[n].bitpend);
|
||||
s.array(pixelcache[n].data);
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "hg51b.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto HG51B::lock() -> void {
|
||||
io.lock = 1;
|
||||
}
|
||||
|
||||
auto HG51B::halt() -> void {
|
||||
io.halt = 1;
|
||||
}
|
||||
|
||||
auto HG51B::wait(uint24 address) -> uint {
|
||||
if(isROM(address)) return 1 + io.wait.rom;
|
||||
if(isRAM(address)) return 1 + io.wait.ram;
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto HG51B::main() -> void {
|
||||
if(io.lock) return step(1);
|
||||
if(io.suspend.enable) return suspend();
|
||||
if(io.cache.enable) return cache(), void();
|
||||
if(io.dma.enable) return dma();
|
||||
if(io.halt) return step(1);
|
||||
return execute();
|
||||
}
|
||||
|
||||
auto HG51B::step(uint clocks) -> void {
|
||||
if(io.bus.enable) {
|
||||
if(io.bus.pending > clocks) {
|
||||
io.bus.pending -= clocks;
|
||||
} else {
|
||||
io.bus.enable = 0;
|
||||
io.bus.pending = 0;
|
||||
if(io.bus.reading) io.bus.reading = 0, r.mdr = read(io.bus.address);
|
||||
if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.mdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto HG51B::execute() -> void {
|
||||
if(!cache()) return halt();
|
||||
auto opcode = programRAM[io.cache.page][r.pc];
|
||||
advance();
|
||||
step(1);
|
||||
instructionTable[opcode]();
|
||||
}
|
||||
|
||||
auto HG51B::advance() -> void {
|
||||
if(++r.pc == 0) {
|
||||
if(io.cache.page == 1) return halt();
|
||||
io.cache.page = 1;
|
||||
if(io.cache.lock[io.cache.page]) return halt();
|
||||
r.pb = r.p;
|
||||
if(!cache()) return halt();
|
||||
}
|
||||
}
|
||||
|
||||
auto HG51B::suspend() -> void {
|
||||
if(!io.suspend.duration) return step(1); //indefinite
|
||||
step(io.suspend.duration);
|
||||
io.suspend.duration = 0;
|
||||
io.suspend.enable = 0;
|
||||
}
|
||||
|
||||
auto HG51B::cache() -> bool {
|
||||
uint24 address = io.cache.base + r.pb * 512;
|
||||
|
||||
//try to use the current page ...
|
||||
if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true;
|
||||
//if it's not valid, try to use the other page ...
|
||||
io.cache.page ^= 1;
|
||||
if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true;
|
||||
//if it's not valid, try to load into the other page ...
|
||||
if(io.cache.lock[io.cache.page]) io.cache.page ^= 1;
|
||||
//if it's locked, try to load into the first page ...
|
||||
if(io.cache.lock[io.cache.page]) return io.cache.enable = 0, false;
|
||||
|
||||
io.cache.address[io.cache.page] = address;
|
||||
for(uint offset : range(256)) {
|
||||
step(wait(address));
|
||||
programRAM[io.cache.page][offset].byte(0) = read(address++);
|
||||
programRAM[io.cache.page][offset].byte(1) = read(address++);
|
||||
}
|
||||
return io.cache.enable = 0, true;
|
||||
}
|
||||
|
||||
auto HG51B::dma() -> void {
|
||||
for(uint offset : range(io.dma.length)) {
|
||||
uint24 source = io.dma.source + offset;
|
||||
uint24 target = io.dma.target + offset;
|
||||
|
||||
if(isROM(source) && isROM(target)) return lock();
|
||||
if(isRAM(source) && isRAM(target)) return lock();
|
||||
|
||||
step(wait(source));
|
||||
auto data = read(source);
|
||||
|
||||
step(wait(target));
|
||||
write(target, data);
|
||||
}
|
||||
|
||||
io.dma.enable = 0;
|
||||
}
|
||||
|
||||
auto HG51B::running() const -> bool {
|
||||
return io.cache.enable || io.dma.enable || io.bus.pending || !io.halt;
|
||||
}
|
||||
|
||||
auto HG51B::busy() const -> bool {
|
||||
return io.cache.enable || io.dma.enable || io.bus.pending;
|
||||
}
|
||||
|
||||
auto HG51B::power() -> void {
|
||||
r = {};
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//Hitachi HG51B S169
|
||||
|
||||
namespace ares {
|
||||
|
||||
struct HG51B {
|
||||
//instruction.cpp
|
||||
HG51B();
|
||||
|
||||
//hg51b.cpp
|
||||
virtual auto step(uint clocks) -> void;
|
||||
virtual auto isROM(uint24 address) -> bool = 0;
|
||||
virtual auto isRAM(uint24 address) -> bool = 0;
|
||||
virtual auto read(uint24 address) -> uint8 = 0;
|
||||
virtual auto write(uint24 address, uint8 data) -> void = 0;
|
||||
virtual auto lock() -> void;
|
||||
virtual auto halt() -> void;
|
||||
auto wait(uint24 address) -> uint;
|
||||
auto main() -> void;
|
||||
auto execute() -> void;
|
||||
auto advance() -> void;
|
||||
auto suspend() -> void;
|
||||
auto cache() -> bool;
|
||||
auto dma() -> void;
|
||||
auto running() const -> bool;
|
||||
auto busy() const -> bool;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
//instructions.cpp
|
||||
auto push() -> void;
|
||||
auto pull() -> void;
|
||||
|
||||
auto algorithmADD(uint24 x, uint24 y) -> uint24;
|
||||
auto algorithmAND(uint24 x, uint24 y) -> uint24;
|
||||
auto algorithmASR(uint24 a, uint5 s) -> uint24;
|
||||
auto algorithmMUL(int24 x, int24 y) -> uint48;
|
||||
auto algorithmOR(uint24 x, uint24 y) -> uint24;
|
||||
auto algorithmROR(uint24 a, uint5 s) -> uint24;
|
||||
auto algorithmSHL(uint24 a, uint5 s) -> uint24;
|
||||
auto algorithmSHR(uint24 a, uint5 s) -> uint24;
|
||||
auto algorithmSUB(uint24 x, uint24 y) -> uint24;
|
||||
auto algorithmSX(uint24 x) -> uint24;
|
||||
auto algorithmXNOR(uint24 x, uint24 y) -> uint24;
|
||||
auto algorithmXOR(uint24 x, uint24 y) -> uint24;
|
||||
|
||||
auto instructionADD(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionADD(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionAND(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionAND(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionASR(uint7 reg) -> void;
|
||||
auto instructionASR(uint5 imm) -> void;
|
||||
auto instructionCLEAR() -> void;
|
||||
auto instructionCMP(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionCMP(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionCMPR(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionCMPR(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionHALT() -> void;
|
||||
auto instructionINC(uint24& reg) -> void;
|
||||
auto instructionJMP(uint8 data, uint1 far, const uint1& take) -> void;
|
||||
auto instructionJSR(uint8 data, uint1 far, const uint1& take) -> void;
|
||||
auto instructionLD(uint24& out, uint7 reg) -> void;
|
||||
auto instructionLD(uint15& out, uint4 reg) -> void;
|
||||
auto instructionLD(uint24& out, uint8 imm) -> void;
|
||||
auto instructionLD(uint15& out, uint8 imm) -> void;
|
||||
auto instructionLDL(uint15& out, uint8 imm) -> void;
|
||||
auto instructionLDH(uint15& out, uint7 imm) -> void;
|
||||
auto instructionMUL(uint7 reg) -> void;
|
||||
auto instructionMUL(uint8 imm) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
auto instructionOR(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionOR(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionRDRAM(uint2 byte, uint24& a) -> void;
|
||||
auto instructionRDRAM(uint2 byte, uint8 imm) -> void;
|
||||
auto instructionRDROM(uint24& reg) -> void;
|
||||
auto instructionRDROM(uint10 imm) -> void;
|
||||
auto instructionROR(uint7 reg) -> void;
|
||||
auto instructionROR(uint5 imm) -> void;
|
||||
auto instructionRTS() -> void;
|
||||
auto instructionSHL(uint7 reg) -> void;
|
||||
auto instructionSHL(uint5 imm) -> void;
|
||||
auto instructionSHR(uint7 reg) -> void;
|
||||
auto instructionSHR(uint5 imm) -> void;
|
||||
auto instructionSKIP(uint1 take, const uint1& flag) -> void;
|
||||
auto instructionST(uint7 reg, uint24& in) -> void;
|
||||
auto instructionSUB(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionSUB(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionSUBR(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionSUBR(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionSWAP(uint24& a, uint4 reg) -> void;
|
||||
auto instructionSXB() -> void;
|
||||
auto instructionSXW() -> void;
|
||||
auto instructionWAIT() -> void;
|
||||
auto instructionWRRAM(uint2 byte, uint24& a) -> void;
|
||||
auto instructionWRRAM(uint2 byte, uint8 imm) -> void;
|
||||
auto instructionXNOR(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionXNOR(uint8 imm, uint5 shift) -> void;
|
||||
auto instructionXOR(uint7 reg, uint5 shift) -> void;
|
||||
auto instructionXOR(uint8 imm, uint5 shift) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint16 programRAM[2][256]; //instruction cache
|
||||
uint24 dataROM[1024];
|
||||
uint8 dataRAM[3072];
|
||||
|
||||
//registers.cpp
|
||||
auto readRegister(uint7 address) -> uint24;
|
||||
auto writeRegister(uint7 address, uint24 data) -> void;
|
||||
|
||||
protected:
|
||||
struct Registers {
|
||||
uint15 pb; //program bank
|
||||
uint8 pc; //program counter
|
||||
|
||||
boolean n; //negative
|
||||
boolean z; //zero
|
||||
boolean c; //carry
|
||||
boolean v; //overflow
|
||||
boolean i; //interrupt
|
||||
|
||||
uint24 a; //accumulator
|
||||
uint15 p; //page register
|
||||
uint48 mul; //multiplier
|
||||
uint24 mdr; //bus memory data register
|
||||
uint24 rom; //data ROM data buffer
|
||||
uint24 ram; //data RAM data buffer
|
||||
uint24 mar; //bus memory address register
|
||||
uint24 dpr; //data RAM address pointer
|
||||
uint24 gpr[16]; //general purpose registers
|
||||
} r;
|
||||
|
||||
struct IO {
|
||||
uint1 lock;
|
||||
uint1 halt = 1;
|
||||
uint1 irq; //0 = enable, 1 = disable
|
||||
uint1 rom = 1; //0 = 2 ROMs, 1 = 1 ROM
|
||||
uint8 vector[32];
|
||||
|
||||
struct Wait {
|
||||
uint3 rom = 3;
|
||||
uint3 ram = 3;
|
||||
} wait;
|
||||
|
||||
struct Suspend {
|
||||
uint1 enable;
|
||||
uint8 duration;
|
||||
} suspend;
|
||||
|
||||
struct Cache {
|
||||
uint1 enable;
|
||||
uint1 page;
|
||||
uint1 lock[2];
|
||||
uint24 address[2]; //cache address is in bytes; so 24-bit
|
||||
uint24 base; //base address is also in bytes
|
||||
uint15 pb;
|
||||
uint8 pc;
|
||||
} cache;
|
||||
|
||||
struct DMA {
|
||||
uint1 enable;
|
||||
uint24 source;
|
||||
uint24 target;
|
||||
uint16 length;
|
||||
} dma;
|
||||
|
||||
struct Bus {
|
||||
uint1 enable;
|
||||
uint1 reading;
|
||||
uint1 writing;
|
||||
uint4 pending;
|
||||
uint24 address;
|
||||
} bus;
|
||||
} io;
|
||||
|
||||
uint23 stack[8];
|
||||
function<void ()> instructionTable[65536];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,639 +0,0 @@
|
||||
HG51B::HG51B() {
|
||||
#define bind(id, name, ...) { \
|
||||
if(instructionTable[id]) throw; \
|
||||
instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
std::integral_constant<uint16_t, bit::test(s)>::value
|
||||
|
||||
static const uint5 shifts[] = {0, 1, 8, 16};
|
||||
|
||||
//NOP
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0000 00.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0000 01.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//JMP imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0000 10f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, 1);
|
||||
}
|
||||
|
||||
//JMP EQ,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0000 11f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.z);
|
||||
}
|
||||
|
||||
//JMP GE,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0001 00f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.c);
|
||||
}
|
||||
|
||||
//JMP MI,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0001 01f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.n);
|
||||
}
|
||||
|
||||
//JMP VS,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0001 10f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.v);
|
||||
}
|
||||
|
||||
//WAIT
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0001 11.. .... ....");
|
||||
bind(opcode | null << 0, WAIT);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0010 00.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//SKIP V
|
||||
for(uint1 take : range( 2))
|
||||
for(uint7 null : range(128)) {
|
||||
auto opcode = pattern("0010 0100 .... ...t");
|
||||
bind(opcode | take << 0 | null << 1, SKIP, take, r.v);
|
||||
}
|
||||
|
||||
//SKIP C
|
||||
for(uint1 take : range( 2))
|
||||
for(uint7 null : range(128)) {
|
||||
auto opcode = pattern("0010 0101 .... ...t");
|
||||
bind(opcode | take << 0 | null << 1, SKIP, take, r.c);
|
||||
}
|
||||
|
||||
//SKIP Z
|
||||
for(uint1 take : range( 2))
|
||||
for(uint7 null : range(128)) {
|
||||
auto opcode = pattern("0010 0110 .... ...t");
|
||||
bind(opcode | take << 0 | null << 1, SKIP, take, r.z);
|
||||
}
|
||||
|
||||
//SKIP N
|
||||
for(uint1 take : range( 2))
|
||||
for(uint7 null : range(128)) {
|
||||
auto opcode = pattern("0010 0111 .... ...t");
|
||||
bind(opcode | take << 0 | null << 1, SKIP, take, r.n);
|
||||
}
|
||||
|
||||
//JSR
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0010 10f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, 1);
|
||||
}
|
||||
|
||||
//JSR EQ,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0010 11f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.z);
|
||||
}
|
||||
|
||||
//JSR GE,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0011 00f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.c);
|
||||
}
|
||||
|
||||
//JSR MI,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0011 01f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.n);
|
||||
}
|
||||
|
||||
//JSR VS,imm
|
||||
for(uint8 data : range(256))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint1 far : range( 2)) {
|
||||
auto opcode = pattern("0011 10f. dddd dddd");
|
||||
bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.v);
|
||||
}
|
||||
|
||||
//RTS
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0011 11.. .... ....");
|
||||
bind(opcode | null << 0, RTS);
|
||||
}
|
||||
|
||||
//INC MAR
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0100 00.. .... ....");
|
||||
bind(opcode | null << 0, INC, r.mar);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0100 01.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//CMPR A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("0100 10ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, CMPR, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//CMPR A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("0100 11ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, CMPR, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//CMP A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("0101 00ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, CMP, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//CMP A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("0101 01ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, CMP, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0101 1000 .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//SXB A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0101 1001 .... ....");
|
||||
bind(opcode | null << 0, SXB);
|
||||
}
|
||||
|
||||
//SXW A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0101 1010 .... ....");
|
||||
bind(opcode | null << 0, SXW);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0101 1011 .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0101 11.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//LD A,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2)) {
|
||||
auto opcode = pattern("0110 0000 .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, LD, r.a, reg);
|
||||
}
|
||||
|
||||
//LD MDR,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2)) {
|
||||
auto opcode = pattern("0110 0001 .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, LD, r.mdr, reg);
|
||||
}
|
||||
|
||||
//LD MAR,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2)) {
|
||||
auto opcode = pattern("0110 0010 .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, LD, r.mar, reg);
|
||||
}
|
||||
|
||||
//LD P,reg
|
||||
for(uint4 reg : range(16))
|
||||
for(uint4 null : range(16)) {
|
||||
auto opcode = pattern("0110 0011 .... rrrr");
|
||||
bind(opcode | reg << 0 | null << 4, LD, r.p, reg);
|
||||
}
|
||||
|
||||
//LD A,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 0100 iiii iiii");
|
||||
bind(opcode | imm << 0, LD, r.a, imm);
|
||||
}
|
||||
|
||||
//LD MDR,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 0101 iiii iiii");
|
||||
bind(opcode | imm << 0, LD, r.mdr, imm);
|
||||
}
|
||||
|
||||
//LD MAR,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 0110 iiii iiii");
|
||||
bind(opcode | imm << 0, LD, r.mar, imm);
|
||||
}
|
||||
|
||||
//LD P,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 0111 iiii iiii");
|
||||
bind(opcode | imm << 0, LD, r.p, imm);
|
||||
}
|
||||
|
||||
//RDRAM 0,A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0110 1000 .... ....");
|
||||
bind(opcode | null << 0, RDRAM, 0, r.a);
|
||||
}
|
||||
|
||||
//RDRAM 1,A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0110 1001 .... ....");
|
||||
bind(opcode | null << 0, RDRAM, 1, r.a);
|
||||
}
|
||||
|
||||
//RDRAM 2,A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0110 1010 .... ....");
|
||||
bind(opcode | null << 0, RDRAM, 2, r.a);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0110 1011 .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//RDRAM 0,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 1100 iiii iiii");
|
||||
bind(opcode | imm << 0, RDRAM, 0, imm);
|
||||
}
|
||||
|
||||
//RDRAM 1,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 1101 iiii iiii");
|
||||
bind(opcode | imm << 0, RDRAM, 1, imm);
|
||||
}
|
||||
|
||||
//RDRAM 2,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0110 1110 iiii iiii");
|
||||
bind(opcode | imm << 0, RDRAM, 2, imm);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("0110 1111 .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//RDROM A
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0111 00.. .... ....");
|
||||
bind(opcode | null << 0, RDROM, r.a);
|
||||
}
|
||||
|
||||
//RDROM imm
|
||||
for(uint10 imm : range(1024)) {
|
||||
auto opcode = pattern("0111 01ii iiii iiii");
|
||||
bind(opcode | imm << 0, RDROM, imm);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("0111 10.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//LD PL,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("0111 1100 iiii iiii");
|
||||
bind(opcode | imm << 0, LDL, r.p, imm);
|
||||
}
|
||||
|
||||
//LD PH,imm
|
||||
for(uint7 imm : range(128))
|
||||
for(uint1 null : range( 2)) {
|
||||
auto opcode = pattern("0111 1101 .iii iiii");
|
||||
bind(opcode | imm << 0 | null << 7, LDH, r.p, imm);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint9 null : range(512)) {
|
||||
auto opcode = pattern("0111 111. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//ADD A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1000 00ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, ADD, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//ADD A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1000 01ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, ADD, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//SUBR A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1000 10ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, SUBR, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//SUBR A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1000 11ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, SUBR, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//SUB A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1001 00ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, SUB, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//SUB A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1001 01ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, SUB, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//MUL reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint3 null : range( 8)) {
|
||||
auto opcode = pattern("1001 10.. .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, MUL, reg);
|
||||
}
|
||||
|
||||
//MUL imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 null : range( 4)) {
|
||||
auto opcode = pattern("1001 11.. iiii iiii");
|
||||
bind(opcode | imm << 0 | null << 8, MUL, imm);
|
||||
}
|
||||
|
||||
//XNOR A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1010 00ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, XNOR, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//XNOR A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1010 01ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, XNOR, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//XOR A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1010 10ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, XOR, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//XOR A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1010 11ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, XOR, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//AND A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1011 00ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, AND, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//AND A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1011 01ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, AND, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//OR A<<s,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1011 10ss .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7 | shift << 8, OR, reg, shifts[shift]);
|
||||
}
|
||||
|
||||
//OR A<<s,imm
|
||||
for(uint8 imm : range(256))
|
||||
for(uint2 shift : range( 4)) {
|
||||
auto opcode = pattern("1011 11ss iiii iiii");
|
||||
bind(opcode | imm << 0 | shift << 8, OR, imm, shifts[shift]);
|
||||
}
|
||||
|
||||
//SHR A,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint3 null : range( 8)) {
|
||||
auto opcode = pattern("1100 00.. .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, SHR, reg);
|
||||
}
|
||||
|
||||
//SHR A,imm
|
||||
for(uint5 imm : range(32))
|
||||
for(uint5 null : range(32)) {
|
||||
auto opcode = pattern("1100 01.. ...i iiii");
|
||||
bind(opcode | imm << 0 | null << 5, SHR, imm);
|
||||
}
|
||||
|
||||
//ASR A,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint3 null : range( 8)) {
|
||||
auto opcode = pattern("1100 10.. .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, ASR, reg);
|
||||
}
|
||||
|
||||
//ASR A,imm
|
||||
for(uint5 imm : range(32))
|
||||
for(uint5 null : range(32)) {
|
||||
auto opcode = pattern("1100 11.. ...i iiii");
|
||||
bind(opcode | imm << 0 | null << 5, ASR, imm);
|
||||
}
|
||||
|
||||
//ROR A,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint3 null : range( 8)) {
|
||||
auto opcode = pattern("1101 00.. .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, ROR, reg);
|
||||
}
|
||||
|
||||
//ROR A,imm
|
||||
for(uint5 imm : range(32))
|
||||
for(uint5 null : range(32)) {
|
||||
auto opcode = pattern("1101 01.. ...i iiii");
|
||||
bind(opcode | imm << 0 | null << 5, ROR, imm);
|
||||
}
|
||||
|
||||
//SHL A,reg
|
||||
for(uint7 reg : range(128))
|
||||
for(uint3 null : range( 8)) {
|
||||
auto opcode = pattern("1101 10.. .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, SHL, reg);
|
||||
}
|
||||
|
||||
//SHL A,imm
|
||||
for(uint5 imm : range(32))
|
||||
for(uint5 null : range(32)) {
|
||||
auto opcode = pattern("1101 11.. ...i iiii");
|
||||
bind(opcode | imm << 0 | null << 5, SHL, imm);
|
||||
}
|
||||
|
||||
//ST reg,A
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2)) {
|
||||
auto opcode = pattern("1110 0000 .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, ST, reg, r.a);
|
||||
}
|
||||
|
||||
//ST reg,MDR
|
||||
for(uint7 reg : range(128))
|
||||
for(uint1 null : range( 2)) {
|
||||
auto opcode = pattern("1110 0001 .rrr rrrr");
|
||||
bind(opcode | reg << 0 | null << 7, ST, reg, r.mdr);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint9 null : range(512)) {
|
||||
auto opcode = pattern("1110 001. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("1110 01.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//WRRAM 0,A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("1110 1000 .... ....");
|
||||
bind(opcode | null << 0, WRRAM, 0, r.a);
|
||||
}
|
||||
|
||||
//WRRAM 1,A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("1110 1001 .... ....");
|
||||
bind(opcode | null << 0, WRRAM, 1, r.a);
|
||||
}
|
||||
|
||||
//WRRAM 2,A
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("1110 1010 .... ....");
|
||||
bind(opcode | null << 0, WRRAM, 2, r.a);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("1110 1011 .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//WRRAM 0,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("1110 1100 iiii iiii");
|
||||
bind(opcode | imm << 0, WRRAM, 0, imm);
|
||||
}
|
||||
|
||||
//WRRAM 1,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("1110 1101 iiii iiii");
|
||||
bind(opcode | imm << 0, WRRAM, 1, imm);
|
||||
}
|
||||
|
||||
//WRRAM 2,imm
|
||||
for(uint8 imm : range(256)) {
|
||||
auto opcode = pattern("1110 1110 iiii iiii");
|
||||
bind(opcode | imm << 0, WRRAM, 2, imm);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint8 null : range(256)) {
|
||||
auto opcode = pattern("1110 1111 .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//SWAP A,Rn
|
||||
for(uint4 reg : range(16))
|
||||
for(uint6 null : range(64)) {
|
||||
auto opcode = pattern("1111 00.. .... rrrr");
|
||||
bind(opcode | reg << 0 | null << 4, SWAP, r.a, reg);
|
||||
}
|
||||
|
||||
//???
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("1111 01.. .... ....");
|
||||
bind(opcode | null << 0, NOP);
|
||||
}
|
||||
|
||||
//CLEAR
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("1111 10.. .... ....");
|
||||
bind(opcode | null << 0, CLEAR);
|
||||
}
|
||||
|
||||
//HALT
|
||||
for(uint10 null : range(1024)) {
|
||||
auto opcode = pattern("1111 11.. .... ....");
|
||||
bind(opcode | null << 0, HALT);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
|
||||
for(uint opcode : range(65536)) {
|
||||
if(!instructionTable[opcode]) throw;
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
auto HG51B::push() -> void {
|
||||
stack[7] = stack[6];
|
||||
stack[6] = stack[5];
|
||||
stack[5] = stack[4];
|
||||
stack[4] = stack[3];
|
||||
stack[3] = stack[2];
|
||||
stack[2] = stack[1];
|
||||
stack[1] = stack[0];
|
||||
stack[0] = r.pb << 8 | r.pc << 0;
|
||||
}
|
||||
|
||||
auto HG51B::pull() -> void {
|
||||
auto pc = stack[0];
|
||||
stack[0] = stack[1];
|
||||
stack[1] = stack[2];
|
||||
stack[2] = stack[3];
|
||||
stack[3] = stack[4];
|
||||
stack[4] = stack[5];
|
||||
stack[5] = stack[6];
|
||||
stack[6] = stack[7];
|
||||
stack[7] = 0x0000;
|
||||
|
||||
r.pb = pc >> 8;
|
||||
r.pc = pc >> 0;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto HG51B::algorithmADD(uint24 x, uint24 y) -> uint24 {
|
||||
int z = x + y;
|
||||
r.n = z & 0x800000;
|
||||
r.z = (uint24)z == 0;
|
||||
r.c = z > 0xffffff;
|
||||
r.v = ~(x ^ y) & (x ^ z) & 0x800000;
|
||||
return z;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmAND(uint24 x, uint24 y) -> uint24 {
|
||||
x = x & y;
|
||||
r.n = x & 0x800000;
|
||||
r.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmASR(uint24 a, uint5 s) -> uint24 {
|
||||
if(s > 24) s = 0;
|
||||
a = (int24)a >> s;
|
||||
r.n = a & 0x800000;
|
||||
r.z = a == 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmMUL(int24 x, int24 y) -> uint48 {
|
||||
return (int48)x * (int48)y;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmOR(uint24 x, uint24 y) -> uint24 {
|
||||
x = x | y;
|
||||
r.n = x & 0x800000;
|
||||
r.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmROR(uint24 a, uint5 s) -> uint24 {
|
||||
if(s > 24) s = 0;
|
||||
a = (a >> s) | (a << 24 - s);
|
||||
r.n = a & 0x800000;
|
||||
r.z = a == 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmSHL(uint24 a, uint5 s) -> uint24 {
|
||||
if(s > 24) s = 0;
|
||||
a = a << s;
|
||||
r.n = a & 0x800000;
|
||||
r.z = a == 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmSHR(uint24 a, uint5 s) -> uint24 {
|
||||
if(s > 24) s = 0;
|
||||
a = a >> s;
|
||||
r.n = a & 0x800000;
|
||||
r.z = a == 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmSUB(uint24 x, uint24 y) -> uint24 {
|
||||
int z = x - y;
|
||||
r.n = z & 0x800000;
|
||||
r.z = (uint24)z == 0;
|
||||
r.c = z >= 0;
|
||||
r.v = ~(x ^ y) & (x ^ z) & 0x800000;
|
||||
return z;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmSX(uint24 x) -> uint24 {
|
||||
r.n = x & 0x800000;
|
||||
r.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmXNOR(uint24 x, uint24 y) -> uint24 {
|
||||
x = ~x ^ y;
|
||||
r.n = x & 0x800000;
|
||||
r.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
auto HG51B::algorithmXOR(uint24 x, uint24 y) -> uint24 {
|
||||
x = x ^ y;
|
||||
r.n = x & 0x800000;
|
||||
r.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto HG51B::instructionADD(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmADD(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionADD(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmADD(r.a << shift, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionAND(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmAND(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionAND(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmAND(r.a << shift, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionASR(uint7 reg) -> void {
|
||||
r.a = algorithmASR(r.a, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionASR(uint5 imm) -> void {
|
||||
r.a = algorithmASR(r.a, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionCLEAR() -> void {
|
||||
r.a = 0;
|
||||
r.p = 0;
|
||||
r.ram = 0;
|
||||
r.dpr = 0;
|
||||
}
|
||||
|
||||
auto HG51B::instructionCMP(uint7 reg, uint5 shift) -> void {
|
||||
algorithmSUB(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionCMP(uint8 imm, uint5 shift) -> void {
|
||||
algorithmSUB(r.a << shift, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionCMPR(uint7 reg, uint5 shift) -> void {
|
||||
algorithmSUB(readRegister(reg), r.a << shift);
|
||||
}
|
||||
|
||||
auto HG51B::instructionCMPR(uint8 imm, uint5 shift) -> void {
|
||||
algorithmSUB(imm, r.a << shift);
|
||||
}
|
||||
|
||||
auto HG51B::instructionHALT() -> void {
|
||||
halt();
|
||||
}
|
||||
|
||||
auto HG51B::instructionINC(uint24& reg) -> void {
|
||||
reg++;
|
||||
}
|
||||
|
||||
auto HG51B::instructionJMP(uint8 data, uint1 far, const uint1& take) -> void {
|
||||
if(!take) return;
|
||||
if(far) r.pb = r.p;
|
||||
r.pc = data;
|
||||
step(2);
|
||||
}
|
||||
|
||||
auto HG51B::instructionJSR(uint8 data, uint1 far, const uint1& take) -> void {
|
||||
if(!take) return;
|
||||
push();
|
||||
if(far) r.pb = r.p;
|
||||
r.pc = data;
|
||||
step(2);
|
||||
}
|
||||
|
||||
auto HG51B::instructionLD(uint24& out, uint7 reg) -> void {
|
||||
out = readRegister(reg);
|
||||
}
|
||||
|
||||
auto HG51B::instructionLD(uint15& out, uint4 reg) -> void {
|
||||
out = r.gpr[reg];
|
||||
}
|
||||
|
||||
auto HG51B::instructionLD(uint24& out, uint8 imm) -> void {
|
||||
out = imm;
|
||||
}
|
||||
|
||||
auto HG51B::instructionLD(uint15& out, uint8 imm) -> void {
|
||||
out = imm;
|
||||
}
|
||||
|
||||
auto HG51B::instructionLDL(uint15& out, uint8 imm) -> void {
|
||||
out.bit(0,7) = imm;
|
||||
}
|
||||
|
||||
auto HG51B::instructionLDH(uint15& out, uint7 imm) -> void {
|
||||
out.bit(8,14) = imm;
|
||||
}
|
||||
|
||||
auto HG51B::instructionMUL(uint7 reg) -> void {
|
||||
r.mul = algorithmMUL(r.a, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionMUL(uint8 imm) -> void {
|
||||
r.mul = algorithmMUL(r.a, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionNOP() -> void {
|
||||
}
|
||||
|
||||
auto HG51B::instructionOR(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmOR(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionOR(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmOR(r.a << shift, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionRDRAM(uint2 byte, uint24& a) -> void {
|
||||
uint12 address = a;
|
||||
if(address >= 0xc00) address -= 0x400;
|
||||
r.ram.byte(byte) = dataRAM[address];
|
||||
}
|
||||
|
||||
auto HG51B::instructionRDRAM(uint2 byte, uint8 imm) -> void {
|
||||
uint12 address = r.dpr + imm;
|
||||
if(address >= 0xc00) address -= 0x400;
|
||||
r.ram.byte(byte) = dataRAM[address];
|
||||
}
|
||||
|
||||
auto HG51B::instructionRDROM(uint24& reg) -> void {
|
||||
r.rom = dataROM[(uint10)reg];
|
||||
}
|
||||
|
||||
auto HG51B::instructionRDROM(uint10 imm) -> void {
|
||||
r.rom = dataROM[imm];
|
||||
}
|
||||
|
||||
auto HG51B::instructionROR(uint7 reg) -> void {
|
||||
r.a = algorithmROR(r.a, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionROR(uint5 imm) -> void {
|
||||
r.a = algorithmROR(r.a, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionRTS() -> void {
|
||||
pull();
|
||||
step(2);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSKIP(uint1 take, const uint1& flag) -> void {
|
||||
if(flag != take) return;
|
||||
advance();
|
||||
step(1);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSHL(uint7 reg) -> void {
|
||||
r.a = algorithmSHL(r.a, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionSHL(uint5 imm) -> void {
|
||||
r.a = algorithmSHL(r.a, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSHR(uint7 reg) -> void {
|
||||
r.a = algorithmSHR(r.a, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionSHR(uint5 imm) -> void {
|
||||
r.a = algorithmSHR(r.a, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionST(uint7 reg, uint24& in) -> void {
|
||||
writeRegister(reg, in);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSUB(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmSUB(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionSUB(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmSUB(r.a << shift, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSUBR(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmSUB(readRegister(reg), r.a << shift);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSUBR(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmSUB(imm, r.a << shift);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSWAP(uint24& a, uint4 reg) -> void {
|
||||
swap(a, r.gpr[reg]);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSXB() -> void {
|
||||
r.a = algorithmSX((int8)r.a);
|
||||
}
|
||||
|
||||
auto HG51B::instructionSXW() -> void {
|
||||
r.a = algorithmSX((int16)r.a);
|
||||
}
|
||||
|
||||
auto HG51B::instructionWAIT() -> void {
|
||||
if(!io.bus.enable) return;
|
||||
return step(io.bus.pending);
|
||||
}
|
||||
|
||||
auto HG51B::instructionWRRAM(uint2 byte, uint24& a) -> void {
|
||||
uint12 address = a;
|
||||
if(address >= 0xc00) address -= 0x400;
|
||||
switch(byte) {
|
||||
case 0: dataRAM[address] = r.ram >> 0; break;
|
||||
case 1: dataRAM[address] = r.ram >> 8; break;
|
||||
case 2: dataRAM[address] = r.ram >> 16; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto HG51B::instructionWRRAM(uint2 byte, uint8 imm) -> void {
|
||||
uint12 address = r.dpr + imm;
|
||||
if(address >= 0xc00) address -= 0x400;
|
||||
switch(byte) {
|
||||
case 0: dataRAM[address] = r.ram >> 0; break;
|
||||
case 1: dataRAM[address] = r.ram >> 8; break;
|
||||
case 2: dataRAM[address] = r.ram >> 16; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto HG51B::instructionXNOR(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmXNOR(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionXNOR(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmXNOR(r.a << shift, imm);
|
||||
}
|
||||
|
||||
auto HG51B::instructionXOR(uint7 reg, uint5 shift) -> void {
|
||||
r.a = algorithmXOR(r.a << shift, readRegister(reg));
|
||||
}
|
||||
|
||||
auto HG51B::instructionXOR(uint8 imm, uint5 shift) -> void {
|
||||
r.a = algorithmXOR(r.a << shift, imm);
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
auto HG51B::readRegister(uint7 address) -> uint24 {
|
||||
switch(address) {
|
||||
case 0x01: return r.mul.bit(24,47);
|
||||
case 0x02: return r.mul.bit( 0,23);
|
||||
case 0x03: return r.mdr;
|
||||
case 0x08: return r.rom;
|
||||
case 0x0c: return r.ram;
|
||||
case 0x13: return r.mar;
|
||||
case 0x1c: return r.dpr;
|
||||
case 0x20: return r.pc;
|
||||
case 0x28: return r.p;
|
||||
case 0x2e:
|
||||
io.bus.enable = 1;
|
||||
io.bus.reading = 1;
|
||||
io.bus.pending = 1 + io.wait.rom;
|
||||
io.bus.address = r.mar;
|
||||
return 0x000000;
|
||||
case 0x2f:
|
||||
io.bus.enable = 1;
|
||||
io.bus.reading = 1;
|
||||
io.bus.pending = 1 + io.wait.ram;
|
||||
io.bus.address = r.mar;
|
||||
return 0x000000;
|
||||
|
||||
//constant registers
|
||||
case 0x50: return 0x000000;
|
||||
case 0x51: return 0xffffff;
|
||||
case 0x52: return 0x00ff00;
|
||||
case 0x53: return 0xff0000;
|
||||
case 0x54: return 0x00ffff;
|
||||
case 0x55: return 0xffff00;
|
||||
case 0x56: return 0x800000;
|
||||
case 0x57: return 0x7fffff;
|
||||
case 0x58: return 0x008000;
|
||||
case 0x59: return 0x007fff;
|
||||
case 0x5a: return 0xff7fff;
|
||||
case 0x5b: return 0xffff7f;
|
||||
case 0x5c: return 0x010000;
|
||||
case 0x5d: return 0xfeffff;
|
||||
case 0x5e: return 0x000100;
|
||||
case 0x5f: return 0x00feff;
|
||||
|
||||
//general purpose registers
|
||||
case 0x60: case 0x70: return r.gpr[ 0];
|
||||
case 0x61: case 0x71: return r.gpr[ 1];
|
||||
case 0x62: case 0x72: return r.gpr[ 2];
|
||||
case 0x63: case 0x73: return r.gpr[ 3];
|
||||
case 0x64: case 0x74: return r.gpr[ 4];
|
||||
case 0x65: case 0x75: return r.gpr[ 5];
|
||||
case 0x66: case 0x76: return r.gpr[ 6];
|
||||
case 0x67: case 0x77: return r.gpr[ 7];
|
||||
case 0x68: case 0x78: return r.gpr[ 8];
|
||||
case 0x69: case 0x79: return r.gpr[ 9];
|
||||
case 0x6a: case 0x7a: return r.gpr[10];
|
||||
case 0x6b: case 0x7b: return r.gpr[11];
|
||||
case 0x6c: case 0x7c: return r.gpr[12];
|
||||
case 0x6d: case 0x7d: return r.gpr[13];
|
||||
case 0x6e: case 0x7e: return r.gpr[14];
|
||||
case 0x6f: case 0x7f: return r.gpr[15];
|
||||
}
|
||||
|
||||
return 0x000000; //verified
|
||||
}
|
||||
|
||||
auto HG51B::writeRegister(uint7 address, uint24 data) -> void {
|
||||
switch(address) {
|
||||
case 0x01: r.mul.bit(24,47) = data; return;
|
||||
case 0x02: r.mul.bit( 0,23) = data; return;
|
||||
case 0x03: r.mdr = data; return;
|
||||
case 0x08: r.rom = data; return;
|
||||
case 0x0c: r.ram = data; return;
|
||||
case 0x13: r.mar = data; return;
|
||||
case 0x1c: r.dpr = data; return;
|
||||
case 0x20: r.pc = data; return;
|
||||
case 0x28: r.p = data; return;
|
||||
case 0x2e:
|
||||
io.bus.enable = 1;
|
||||
io.bus.writing = 1;
|
||||
io.bus.pending = 1 + io.wait.rom;
|
||||
io.bus.address = r.mar;
|
||||
return;
|
||||
case 0x2f:
|
||||
io.bus.enable = 1;
|
||||
io.bus.writing = 1;
|
||||
io.bus.pending = 1 + io.wait.ram;
|
||||
io.bus.address = r.mar;
|
||||
return;
|
||||
|
||||
case 0x60: case 0x70: r.gpr[ 0] = data; return;
|
||||
case 0x61: case 0x71: r.gpr[ 1] = data; return;
|
||||
case 0x62: case 0x72: r.gpr[ 2] = data; return;
|
||||
case 0x63: case 0x73: r.gpr[ 3] = data; return;
|
||||
case 0x64: case 0x74: r.gpr[ 4] = data; return;
|
||||
case 0x65: case 0x75: r.gpr[ 5] = data; return;
|
||||
case 0x66: case 0x76: r.gpr[ 6] = data; return;
|
||||
case 0x67: case 0x77: r.gpr[ 7] = data; return;
|
||||
case 0x68: case 0x78: r.gpr[ 8] = data; return;
|
||||
case 0x69: case 0x79: r.gpr[ 9] = data; return;
|
||||
case 0x6a: case 0x7a: r.gpr[10] = data; return;
|
||||
case 0x6b: case 0x7b: r.gpr[11] = data; return;
|
||||
case 0x6c: case 0x7c: r.gpr[12] = data; return;
|
||||
case 0x6d: case 0x7d: r.gpr[13] = data; return;
|
||||
case 0x6e: case 0x7e: r.gpr[14] = data; return;
|
||||
case 0x6f: case 0x7f: r.gpr[15] = data; return;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
auto HG51B::serialize(serializer& s) -> void {
|
||||
s.array(programRAM[0]);
|
||||
s.array(programRAM[1]);
|
||||
s.array(dataRAM);
|
||||
|
||||
s.integer(r.pb);
|
||||
s.integer(r.pc);
|
||||
|
||||
s.boolean(r.n);
|
||||
s.boolean(r.z);
|
||||
s.boolean(r.c);
|
||||
s.boolean(r.v);
|
||||
s.boolean(r.i);
|
||||
|
||||
s.integer(r.a);
|
||||
s.integer(r.p);
|
||||
s.integer(r.mul);
|
||||
s.integer(r.mdr);
|
||||
s.integer(r.rom);
|
||||
s.integer(r.ram);
|
||||
s.integer(r.mar);
|
||||
s.integer(r.dpr);
|
||||
s.array(r.gpr);
|
||||
|
||||
s.integer(io.lock);
|
||||
s.integer(io.halt);
|
||||
s.integer(io.irq);
|
||||
s.integer(io.rom);
|
||||
s.array(io.vector);
|
||||
|
||||
s.integer(io.wait.rom);
|
||||
s.integer(io.wait.ram);
|
||||
|
||||
s.integer(io.suspend.enable);
|
||||
s.integer(io.suspend.duration);
|
||||
|
||||
s.integer(io.cache.enable);
|
||||
s.integer(io.cache.page);
|
||||
s.array(io.cache.lock);
|
||||
s.array(io.cache.address);
|
||||
s.integer(io.cache.base);
|
||||
s.integer(io.cache.pb);
|
||||
s.integer(io.cache.pc);
|
||||
|
||||
s.integer(io.dma.enable);
|
||||
s.integer(io.dma.source);
|
||||
s.integer(io.dma.target);
|
||||
s.integer(io.dma.length);
|
||||
|
||||
s.integer(io.bus.enable);
|
||||
s.integer(io.bus.reading);
|
||||
s.integer(io.bus.writing);
|
||||
s.integer(io.bus.pending);
|
||||
s.integer(io.bus.address);
|
||||
|
||||
s.array(stack);
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
auto HuC6280::algorithmADC(uint8 i) -> uint8 {
|
||||
int16 o;
|
||||
if(!D) {
|
||||
o = A + i + C;
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
} else {
|
||||
idle();
|
||||
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
|
||||
if(o > 0x09) o += 0x06;
|
||||
C = o > 0x0f;
|
||||
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
|
||||
if(o > 0x9f) o += 0x60;
|
||||
}
|
||||
C = o.bit(8);
|
||||
Z = uint8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmAND(uint8 i) -> uint8 {
|
||||
uint8 o = A & i;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmASL(uint8 i) -> uint8 {
|
||||
C = i.bit(7);
|
||||
i <<= 1;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmBIT(uint8 i) -> uint8 {
|
||||
Z = (A & i) == 0;
|
||||
V = i.bit(6);
|
||||
N = i.bit(7);
|
||||
return A;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmCMP(uint8 i) -> uint8 {
|
||||
uint9 o = A - i;
|
||||
C = !o.bit(8);
|
||||
Z = uint8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return A;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmCPX(uint8 i) -> uint8 {
|
||||
uint9 o = X - i;
|
||||
C = !o.bit(8);
|
||||
Z = uint8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return X;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmCPY(uint8 i) -> uint8 {
|
||||
uint9 o = Y - i;
|
||||
C = !o.bit(8);
|
||||
Z = uint8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return Y;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmDEC(uint8 i) -> uint8 {
|
||||
i--;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmEOR(uint8 i) -> uint8 {
|
||||
uint8 o = A ^ i;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmINC(uint8 i) -> uint8 {
|
||||
i++;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmLD(uint8 i) -> uint8 {
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmLSR(uint8 i) -> uint8 {
|
||||
C = i.bit(0);
|
||||
i >>= 1;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmORA(uint8 i) -> uint8 {
|
||||
uint8 o = A | i;
|
||||
Z = o == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmROL(uint8 i) -> uint8 {
|
||||
bool c = C;
|
||||
C = i.bit(7);
|
||||
i = i << 1 | c;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmROR(uint8 i) -> uint8 {
|
||||
bool c = C;
|
||||
C = i.bit(0);
|
||||
i = c << 7 | i >> 1;
|
||||
Z = i == 0;
|
||||
N = i.bit(7);
|
||||
return i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmSBC(uint8 i) -> uint8 {
|
||||
i ^= 0xff;
|
||||
int16 o;
|
||||
if(!D) {
|
||||
o = A + i + C;
|
||||
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||
} else {
|
||||
idle();
|
||||
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
|
||||
if(o <= 0x0f) o -= 0x06;
|
||||
C = o > 0x0f;
|
||||
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
|
||||
if(o <= 0xff) o -= 0x60;
|
||||
}
|
||||
C = o.bit(8);
|
||||
Z = uint8(o) == 0;
|
||||
N = o.bit(7);
|
||||
return o;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmTRB(uint8 i) -> uint8 {
|
||||
Z = (A & i) == 0;
|
||||
V = i.bit(6);
|
||||
N = i.bit(7);
|
||||
return ~A & i;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmTSB(uint8 i) -> uint8 {
|
||||
Z = (A & i) == 0;
|
||||
V = i.bit(6);
|
||||
N = i.bit(7);
|
||||
return A | i;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto HuC6280::algorithmTAI(uint16& source, uint16& target, bool alternate) -> void {
|
||||
!alternate ? source++ : source--;
|
||||
target++;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmTDD(uint16& source, uint16& target, bool) -> void {
|
||||
source--;
|
||||
target--;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmTIA(uint16& source, uint16& target, bool alternate) -> void {
|
||||
source++;
|
||||
!alternate ? target++ : target--;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmTII(uint16& source, uint16& target, bool) -> void {
|
||||
source++;
|
||||
target++;
|
||||
}
|
||||
|
||||
auto HuC6280::algorithmTIN(uint16& source, uint16& target, bool) -> void {
|
||||
source++;
|
||||
}
|
||||
@@ -1,459 +0,0 @@
|
||||
auto HuC6280::disassembleInstruction() -> string {
|
||||
uint16 pc = r.pc;
|
||||
maybe<uint24> effectiveAddress;
|
||||
string s;
|
||||
|
||||
auto readByte = [&]() -> uint8 {
|
||||
uint8 data = read(MPR[pc >> 13], pc & 0x1fff);
|
||||
return pc++, data;
|
||||
};
|
||||
|
||||
auto readWord = [&]() -> uint16 {
|
||||
uint16 data = readByte() << 0;
|
||||
return data | readByte() << 8;
|
||||
};
|
||||
|
||||
auto computeAbsolute = [&](uint16 address) {
|
||||
effectiveAddress = MPR[address >> 13] << 16 | address & 0x1fff;
|
||||
};
|
||||
|
||||
auto computeIndirect = [&](uint8 address) {
|
||||
uint16 absolute = 0;
|
||||
absolute |= read(MPR[1], address + 0) << 0;
|
||||
absolute |= read(MPR[1], address + 1) << 8;
|
||||
effectiveAddress = absolute;
|
||||
};
|
||||
|
||||
auto computeIndirectX = [&](uint8 address) {
|
||||
uint16 absolute = 0;
|
||||
absolute |= read(MPR[1], address + r.x + 0) << 0;
|
||||
absolute |= read(MPR[1], address + r.x + 1) << 8;
|
||||
effectiveAddress = absolute;
|
||||
};
|
||||
|
||||
auto computeIndirectY = [&](uint8 address) {
|
||||
uint16 absolute = 0;
|
||||
absolute |= read(MPR[1], address + 0) << 0;
|
||||
absolute |= read(MPR[1], address + 1) << 8;
|
||||
effectiveAddress = absolute + r.y;
|
||||
};
|
||||
|
||||
auto computeIndirectLong = [&](uint16 address, uint8 index = 0) {
|
||||
uint16 absolute = 0;
|
||||
absolute |= read(MPR[address >> 13], address & 0x1fff) << 0; address++;
|
||||
absolute |= read(MPR[address >> 13], address & 0x1fff) << 8;
|
||||
effectiveAddress = absolute + index;
|
||||
};
|
||||
|
||||
auto computeZeroPage = [&](uint8 address) {
|
||||
effectiveAddress = MPR[1] << 16 | address;
|
||||
};
|
||||
|
||||
auto absolute = [&]() -> string {
|
||||
auto address = readWord();
|
||||
computeAbsolute(address);
|
||||
return {"$", hex(address, 4L)};
|
||||
};
|
||||
|
||||
auto absoluteX = [&]() -> string {
|
||||
auto address = readWord();
|
||||
computeAbsolute(address + r.x);
|
||||
return {"$", hex(address, 4L), ",x"};
|
||||
};
|
||||
|
||||
auto absoluteY = [&]() -> string {
|
||||
auto address = readWord();
|
||||
computeAbsolute(address + r.y);
|
||||
return {"$", hex(address, 4L), ",y"};
|
||||
};
|
||||
|
||||
auto immediate = [&]() -> string {
|
||||
return {"#$", hex(readByte(), 2L)};
|
||||
};
|
||||
|
||||
auto indirect = [&]() -> string {
|
||||
auto indirect = readByte();
|
||||
computeIndirect(indirect);
|
||||
return {"($", hex(indirect, 2L), ")"};
|
||||
};
|
||||
|
||||
auto indirectX = [&]() -> string {
|
||||
auto indirect = readByte();
|
||||
computeIndirectX(indirect);
|
||||
return {"($", hex(indirect, 2L), ",x)"};
|
||||
};
|
||||
|
||||
auto indirectY = [&]() -> string {
|
||||
auto indirect = readByte();
|
||||
computeIndirectY(indirect);
|
||||
return {"($", hex(indirect, 2L), "),y"};
|
||||
};
|
||||
|
||||
auto indirectLong = [&]() -> string {
|
||||
auto address = readWord();
|
||||
computeIndirectLong(address);
|
||||
return {"($", hex(address, 4L), ")"};
|
||||
};
|
||||
|
||||
auto indirectLongX = [&]() -> string {
|
||||
auto address = readWord();
|
||||
computeIndirectLong(address, r.x);
|
||||
return {"($", hex(readWord(), 4L), ",x)"};
|
||||
};
|
||||
|
||||
auto relative = [&]() -> string {
|
||||
auto displacement = readByte();
|
||||
computeAbsolute(pc + (int8)displacement);
|
||||
return {"$", hex(pc + (int8)displacement, 4L)};
|
||||
};
|
||||
|
||||
auto zeropage = [&]() -> string {
|
||||
auto zeroPage = readByte();
|
||||
computeZeroPage(zeroPage);
|
||||
return {"$", hex(zeroPage, 2L)};
|
||||
};
|
||||
|
||||
auto zeropageX = [&]() -> string {
|
||||
auto zeroPage = readByte();
|
||||
computeZeroPage(zeroPage + r.x);
|
||||
return {"$", hex(zeroPage, 2L), ",x"};
|
||||
};
|
||||
|
||||
auto zeropageY = [&]() -> string {
|
||||
auto zeroPage = readByte();
|
||||
computeZeroPage(zeroPage + r.y);
|
||||
return {"$", hex(zeroPage, 2L), ",y"};
|
||||
};
|
||||
|
||||
auto immediateAbsolute = [&](string index = "") -> string {
|
||||
auto immediate = readByte();
|
||||
auto absolute = readWord();
|
||||
computeAbsolute(absolute + (index == "x" ? r.x : (uint8)0));
|
||||
if(index) index.prepend(",");
|
||||
return {"#$", hex(immediate, 2L), ",$", hex(absolute, 4L), index};
|
||||
};
|
||||
|
||||
auto immediateZeropage = [&](string index = "") -> string {
|
||||
auto immediate = readByte();
|
||||
auto zeroPage = readByte();
|
||||
computeZeroPage(zeroPage + (index == "x" ? r.x : (uint8)0));
|
||||
if(index) index.prepend(",");
|
||||
return {"#$", hex(immediate, 2L), ",$", hex(zeroPage, 2L), index};
|
||||
};
|
||||
|
||||
auto zeropageBit = [&](uint3 bit) -> string {
|
||||
auto zeroPage = readByte();
|
||||
computeZeroPage(zeroPage);
|
||||
return {"$", hex(zeroPage, 2L), ":", bit};
|
||||
};
|
||||
|
||||
auto zeropageBitRelative = [&](uint3 bit) -> string {
|
||||
auto zeroPage = readByte();
|
||||
auto displacement = readByte();
|
||||
computeZeroPage(zeroPage);
|
||||
return {"$", hex(zeroPage, 2L), ":", bit, ",$", hex(pc + (int8)displacement, 4L)};
|
||||
};
|
||||
|
||||
auto blockMove = [&]() -> string {
|
||||
auto source = readWord();
|
||||
auto target = readWord();
|
||||
auto length = readWord();
|
||||
return {"$", hex(source, 4L), ",$", hex(target, 4L), ",$", hex(length, 4L)};
|
||||
};
|
||||
|
||||
uint8 opcode = readByte();
|
||||
|
||||
#define op(id, name, ...) case id: o = {name, " ", vector<string>{__VA_ARGS__}.merge(",")}; break;
|
||||
string o;
|
||||
|
||||
#define U
|
||||
switch(opcode) {
|
||||
op(0x00, "brk")
|
||||
op(0x01, "ora", indirectX())
|
||||
op(0x02, "sxy")
|
||||
op(0x03, "st0", immediate())
|
||||
op(0x04, "tsb", zeropage())
|
||||
op(0x05, "ora", zeropage())
|
||||
op(0x06, "asl", zeropage())
|
||||
op(0x07, "rmb", zeropageBit(0))
|
||||
op(0x08, "php")
|
||||
op(0x09, "ora", immediate())
|
||||
op(0x0a, "asl")
|
||||
U op(0x0b, "nop", "$0b")
|
||||
op(0x0c, "tsb", absolute())
|
||||
op(0x0d, "ora", absolute())
|
||||
op(0x0e, "asl", absolute())
|
||||
op(0x0f, "bbr", zeropageBitRelative(0))
|
||||
op(0x10, "bpl", relative())
|
||||
op(0x11, "ora", indirectY())
|
||||
op(0x12, "ora", indirect())
|
||||
op(0x13, "st1", immediate())
|
||||
op(0x14, "trb", zeropage())
|
||||
op(0x15, "ora", zeropageX())
|
||||
op(0x16, "asl", zeropageX())
|
||||
op(0x17, "rmb", zeropageBit(1))
|
||||
op(0x18, "clc")
|
||||
op(0x19, "ora", absoluteY())
|
||||
op(0x1a, "inc")
|
||||
U op(0x1b, "nop", "$1b")
|
||||
op(0x1c, "trb", absolute())
|
||||
op(0x1d, "ora", absoluteX())
|
||||
op(0x1e, "asl", absoluteX())
|
||||
op(0x1f, "bbr", zeropageBitRelative(1))
|
||||
op(0x20, "jsr", absolute())
|
||||
op(0x21, "and", indirectX())
|
||||
op(0x22, "sax")
|
||||
op(0x23, "st2", immediate())
|
||||
op(0x24, "bit", zeropage())
|
||||
op(0x25, "and", zeropage())
|
||||
op(0x26, "rol", zeropage())
|
||||
op(0x27, "rmb", zeropageBit(2))
|
||||
op(0x28, "plp")
|
||||
op(0x29, "and", immediate())
|
||||
op(0x2a, "rol")
|
||||
U op(0x2b, "nop", "$2b")
|
||||
op(0x2c, "bit", absolute())
|
||||
op(0x2d, "and", absolute())
|
||||
op(0x2e, "rol", absolute())
|
||||
op(0x2f, "bbr", zeropageBitRelative(2))
|
||||
op(0x30, "bmi", relative())
|
||||
op(0x31, "and", indirectY())
|
||||
op(0x32, "and", indirect())
|
||||
op(0x34, "bit", zeropageX())
|
||||
op(0x35, "and", zeropageX())
|
||||
op(0x36, "rol", zeropageX())
|
||||
op(0x37, "rmb", zeropageBit(3))
|
||||
op(0x38, "sec")
|
||||
op(0x39, "and", absoluteY())
|
||||
op(0x3a, "dec")
|
||||
U op(0x3b, "nop", "$3b")
|
||||
op(0x3c, "bit", absoluteX())
|
||||
op(0x3d, "and", absoluteX())
|
||||
op(0x3e, "rol", absoluteX())
|
||||
op(0x3f, "bbr", zeropageBitRelative(3))
|
||||
op(0x40, "rti")
|
||||
op(0x41, "eor", indirectX())
|
||||
op(0x42, "say")
|
||||
op(0x43, "tma", immediate())
|
||||
op(0x44, "bsr", relative())
|
||||
op(0x45, "eor", zeropage())
|
||||
op(0x46, "lsr", zeropage())
|
||||
op(0x47, "rmb", zeropageBit(4))
|
||||
op(0x48, "pha")
|
||||
op(0x49, "eor", immediate())
|
||||
op(0x4a, "lsr")
|
||||
U op(0x4b, "nop", "$4b")
|
||||
op(0x4c, "jmp", absolute())
|
||||
op(0x4d, "eor", absolute())
|
||||
op(0x4e, "lsr", absolute())
|
||||
op(0x4f, "bbr", zeropageBitRelative(4))
|
||||
op(0x50, "bvc", relative())
|
||||
op(0x51, "eor", indirectY())
|
||||
op(0x52, "eor", indirect())
|
||||
op(0x53, "tam", immediate())
|
||||
op(0x54, "csl")
|
||||
op(0x55, "eor", zeropageX())
|
||||
op(0x56, "lsr", zeropageX())
|
||||
op(0x57, "rmb", zeropageBit(5))
|
||||
op(0x58, "cli")
|
||||
op(0x59, "eor", absoluteY())
|
||||
op(0x5a, "phy")
|
||||
U op(0x5b, "nop", "$5b")
|
||||
U op(0x5c, "nop", "$5c")
|
||||
op(0x5d, "eor", absoluteX())
|
||||
op(0x5e, "lsr", absoluteX())
|
||||
op(0x5f, "bbr", zeropageBitRelative(5))
|
||||
op(0x60, "rts")
|
||||
op(0x61, "adc", indirectX())
|
||||
op(0x62, "cla")
|
||||
U op(0x63, "nop", "$63")
|
||||
op(0x64, "stz", zeropage())
|
||||
op(0x65, "adc", zeropage())
|
||||
op(0x66, "ror", zeropage())
|
||||
op(0x67, "rmb", zeropageBit(6))
|
||||
op(0x68, "pla")
|
||||
op(0x69, "adc", immediate())
|
||||
op(0x6a, "ror")
|
||||
U op(0x6b, "nop", "$6b")
|
||||
op(0x6c, "jmp", indirectLong())
|
||||
op(0x6d, "adc", absolute())
|
||||
op(0x6e, "ror", absolute())
|
||||
op(0x6f, "bbr", zeropageBitRelative(6))
|
||||
op(0x70, "bvs", relative())
|
||||
op(0x71, "adc", indirectY())
|
||||
op(0x72, "adc", indirect())
|
||||
op(0x73, "tii", blockMove())
|
||||
op(0x74, "stz", zeropageX())
|
||||
op(0x75, "adc", zeropageX())
|
||||
op(0x76, "ror", zeropageX())
|
||||
op(0x77, "rmb", zeropageBit(7))
|
||||
op(0x78, "sei")
|
||||
op(0x79, "adc", absoluteY())
|
||||
op(0x7a, "ply")
|
||||
U op(0x7b, "nop", "$7b")
|
||||
op(0x7c, "jmp", indirectLongX())
|
||||
op(0x7d, "adc", absoluteX())
|
||||
op(0x7e, "ror", absoluteX())
|
||||
op(0x7f, "bbr", zeropageBitRelative(7))
|
||||
op(0x80, "bra", relative())
|
||||
op(0x81, "sta", indirectX())
|
||||
op(0x82, "clx")
|
||||
op(0x83, "tst", immediateZeropage())
|
||||
op(0x84, "sty", zeropage())
|
||||
op(0x85, "sta", zeropage())
|
||||
op(0x86, "stx", zeropage())
|
||||
op(0x87, "smb", zeropageBit(0))
|
||||
op(0x88, "dey")
|
||||
op(0x89, "bit", immediate())
|
||||
op(0x8a, "txa")
|
||||
U op(0x8b, "nop", "$8b")
|
||||
op(0x8c, "sty", absolute())
|
||||
op(0x8d, "sta", absolute())
|
||||
op(0x8e, "stx", absolute())
|
||||
op(0x8f, "bbs", zeropageBitRelative(0))
|
||||
op(0x90, "bcc", relative())
|
||||
op(0x91, "sta", indirectY())
|
||||
op(0x92, "sta", indirect())
|
||||
op(0x93, "tst", immediateAbsolute())
|
||||
op(0x94, "sty", zeropageX())
|
||||
op(0x95, "sta", zeropageX())
|
||||
op(0x96, "stx", zeropageY())
|
||||
op(0x97, "smb", zeropageBit(1))
|
||||
op(0x98, "tya")
|
||||
op(0x99, "sta", absoluteY())
|
||||
op(0x9a, "txs")
|
||||
U op(0x9b, "nop", "$9b")
|
||||
op(0x9c, "stz", absolute())
|
||||
op(0x9d, "sta", absoluteX())
|
||||
op(0x9e, "stz", absoluteX())
|
||||
op(0x9f, "bbs", zeropageBitRelative(1))
|
||||
op(0xa0, "ldy", immediate())
|
||||
op(0xa1, "lda", indirectX())
|
||||
op(0xa2, "ldx", immediate())
|
||||
op(0xa3, "tst", immediateZeropage("x"))
|
||||
op(0xa4, "ldy", zeropage())
|
||||
op(0xa5, "lda", zeropage())
|
||||
op(0xa6, "ldx", zeropage())
|
||||
op(0xa7, "smb", zeropageBit(2))
|
||||
op(0xa8, "tay")
|
||||
op(0xa9, "lda", immediate())
|
||||
op(0xaa, "tax")
|
||||
U op(0xab, "nop", "$ab")
|
||||
op(0xac, "ldy", absolute())
|
||||
op(0xad, "lda", absolute())
|
||||
op(0xae, "ldx", absolute())
|
||||
op(0xaf, "bbs", zeropageBitRelative(2))
|
||||
op(0xb0, "bcs", relative())
|
||||
op(0xb1, "lda", indirectY())
|
||||
op(0xb2, "lda", indirect())
|
||||
op(0xb3, "tst", immediateAbsolute("x"))
|
||||
op(0xb4, "ldy", zeropageX())
|
||||
op(0xb5, "lda", zeropageX())
|
||||
op(0xb6, "ldx", zeropageY())
|
||||
op(0xb7, "smb", zeropageBit(3))
|
||||
op(0xb8, "clv")
|
||||
op(0xb9, "lda", absoluteY())
|
||||
op(0xba, "tsx")
|
||||
U op(0xbb, "nop", "$bb")
|
||||
op(0xbc, "ldy", absoluteX())
|
||||
op(0xbd, "lda", absoluteX())
|
||||
op(0xbe, "ldx", absoluteY())
|
||||
op(0xbf, "bbs", zeropageBitRelative(3))
|
||||
op(0xc0, "cpy", immediate())
|
||||
op(0xc1, "cmp", indirectX())
|
||||
op(0xc2, "cly")
|
||||
op(0xc3, "tdd", blockMove())
|
||||
op(0xc4, "cpy", zeropage())
|
||||
op(0xc5, "cmp", zeropage())
|
||||
op(0xc6, "dec", zeropage())
|
||||
op(0xc7, "smb", zeropageBit(4))
|
||||
op(0xc8, "iny")
|
||||
op(0xc9, "cmp", immediate())
|
||||
op(0xca, "dex")
|
||||
U op(0xcb, "nop", "$cb")
|
||||
op(0xcc, "cpy", absolute())
|
||||
op(0xcd, "cmp", absolute())
|
||||
op(0xce, "dec", absolute())
|
||||
op(0xcf, "bbs", zeropageBitRelative(4))
|
||||
op(0xd0, "bne", relative())
|
||||
op(0xd1, "cmp", indirectY())
|
||||
op(0xd2, "cmp", indirect())
|
||||
op(0xd3, "tin", blockMove())
|
||||
op(0xd4, "csh")
|
||||
op(0xd5, "cmp", zeropageX())
|
||||
op(0xd6, "dec", zeropageX())
|
||||
op(0xd7, "smb", zeropageBit(5))
|
||||
op(0xd8, "cld")
|
||||
op(0xd9, "cmp", absoluteY())
|
||||
op(0xda, "phx")
|
||||
U op(0xdb, "nop", "$db")
|
||||
U op(0xdc, "nop", "$dc")
|
||||
op(0xdd, "cmp", absoluteX())
|
||||
op(0xde, "dec", absoluteX())
|
||||
op(0xdf, "bbs", zeropageBitRelative(5))
|
||||
op(0xe0, "cpx", immediate())
|
||||
op(0xe1, "sbc", indirectX())
|
||||
U op(0xe2, "nop", "$e2")
|
||||
op(0xe3, "tia", blockMove())
|
||||
op(0xe4, "cpx", zeropage())
|
||||
op(0xe5, "sbc", zeropage())
|
||||
op(0xe6, "inc", zeropage())
|
||||
op(0xe7, "smb", zeropageBit(6))
|
||||
op(0xe8, "inx")
|
||||
op(0xe9, "sbc", immediate())
|
||||
op(0xea, "nop")
|
||||
U op(0xeb, "nop", "$eb")
|
||||
op(0xec, "cpx", absolute())
|
||||
op(0xed, "sbc", absolute())
|
||||
op(0xee, "inc", absolute())
|
||||
op(0xef, "bbs", zeropageBitRelative(6))
|
||||
op(0xf0, "beq", relative())
|
||||
op(0xf1, "sbc", indirectY())
|
||||
op(0xf2, "sbc", indirect())
|
||||
op(0xf3, "tai", blockMove())
|
||||
op(0xf4, "set")
|
||||
op(0xf5, "sbc", zeropageX())
|
||||
op(0xf6, "inc", zeropageX())
|
||||
op(0xf7, "smb", zeropageBit(7))
|
||||
op(0xf8, "sed")
|
||||
op(0xf9, "sbc", absoluteY())
|
||||
op(0xfa, "plx")
|
||||
U op(0xfb, "nop", "$fb")
|
||||
U op(0xfc, "nop", "$fc")
|
||||
op(0xfd, "sbc", absoluteX())
|
||||
op(0xfe, "inc", absoluteX())
|
||||
op(0xff, "bbs", zeropageBitRelative(7))
|
||||
}
|
||||
#undef U
|
||||
|
||||
if(!o) o = {"??? (", hex(opcode, 2L), ")"};
|
||||
s.append(pad(o, -21L, ' '));
|
||||
if(effectiveAddress) {
|
||||
s.append(" [", hex(*effectiveAddress, 6L), "]");
|
||||
} else {
|
||||
s.append(" ");
|
||||
}
|
||||
#undef op
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
auto HuC6280::disassembleContext() -> string {
|
||||
string s;
|
||||
s.append( "A:", hex(A, 2L));
|
||||
s.append(" X:", hex(X, 2L));
|
||||
s.append(" Y:", hex(Y, 2L));
|
||||
s.append(" S:", hex(S, 2L));
|
||||
s.append(" PC:", hex(PC, 4L));
|
||||
s.append(" ");
|
||||
s.append(N ? "N" : "n");
|
||||
s.append(V ? "V" : "v");
|
||||
s.append(T ? "T" : "t");
|
||||
s.append(B ? "B" : "b");
|
||||
s.append(D ? "D" : "d");
|
||||
s.append(I ? "I" : "i");
|
||||
s.append(Z ? "Z" : "z");
|
||||
s.append(C ? "C" : "c");
|
||||
s.append(CS == 3 ? "+" : "-");
|
||||
return s;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#include <emulator/emulator.hpp>
|
||||
#include "huc6280.hpp"
|
||||
|
||||
namespace ares {
|
||||
|
||||
#define A r.a
|
||||
#define X r.x
|
||||
#define Y r.y
|
||||
#define S r.s
|
||||
#define PC r.pc
|
||||
#define PCH r.pc.byte(1)
|
||||
#define PCL r.pc.byte(0)
|
||||
#define MPR r.mpr
|
||||
#define MPL r.mpl
|
||||
#define CS r.cs
|
||||
#define P r.p
|
||||
#define C r.p.c
|
||||
#define Z r.p.z
|
||||
#define I r.p.i
|
||||
#define D r.p.d
|
||||
#define B r.p.b
|
||||
#define T r.p.t
|
||||
#define V r.p.v
|
||||
#define N r.p.n
|
||||
#define EA r.ea
|
||||
#define L lastCycle();
|
||||
#define ALU (this->*alu)
|
||||
|
||||
#include "memory.cpp"
|
||||
#include "algorithms.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto HuC6280::power() -> void {
|
||||
random.entropy(Random::Entropy::High);
|
||||
|
||||
A = random();
|
||||
X = random();
|
||||
Y = random();
|
||||
S = random();
|
||||
PC = 0x0000;
|
||||
MPR[0] = random();
|
||||
MPR[1] = random();
|
||||
MPR[2] = random();
|
||||
MPR[3] = random();
|
||||
MPR[4] = random();
|
||||
MPR[5] = random();
|
||||
MPR[6] = random();
|
||||
MPR[7] = 0x00;
|
||||
MPL = 0x00;
|
||||
C = random();
|
||||
Z = random();
|
||||
I = 1;
|
||||
D = 0;
|
||||
B = 1;
|
||||
T = 0;
|
||||
V = random();
|
||||
N = random();
|
||||
CS = 12;
|
||||
|
||||
blockMove = false;
|
||||
}
|
||||
|
||||
#undef A
|
||||
#undef X
|
||||
#undef Y
|
||||
#undef S
|
||||
#undef PC
|
||||
#undef PCH
|
||||
#undef PCL
|
||||
#undef MPR
|
||||
#undef MPL
|
||||
#undef CS
|
||||
#undef P
|
||||
#undef C
|
||||
#undef Z
|
||||
#undef I
|
||||
#undef D
|
||||
#undef B
|
||||
#undef T
|
||||
#undef V
|
||||
#undef N
|
||||
#undef EA
|
||||
#undef L
|
||||
#undef ALU
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
//Hudson Soft HuC6280
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ares {
|
||||
|
||||
struct HuC6280 {
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
virtual auto read(uint8 bank, uint13 address) -> uint8 = 0;
|
||||
virtual auto write(uint8 bank, uint13 address, uint8 data) -> void = 0;
|
||||
virtual auto store(uint2 address, uint8 data) -> void = 0;
|
||||
virtual auto lastCycle() -> void = 0;
|
||||
|
||||
//huc6280.cpp
|
||||
auto power() -> void;
|
||||
|
||||
//memory.cpp
|
||||
inline auto load8(uint8) -> uint8;
|
||||
inline auto load16(uint16) -> uint8;
|
||||
inline auto store8(uint8, uint8) -> void;
|
||||
inline auto store16(uint16, uint8) -> void;
|
||||
|
||||
auto idle() -> void;
|
||||
auto opcode() -> uint8;
|
||||
auto operand() -> uint8;
|
||||
|
||||
auto push(uint8) -> void;
|
||||
auto pull() -> uint8;
|
||||
|
||||
//instructions.cpp
|
||||
using fp = auto (HuC6280::*)(uint8) -> uint8;
|
||||
auto algorithmADC(uint8) -> uint8;
|
||||
auto algorithmAND(uint8) -> uint8;
|
||||
auto algorithmASL(uint8) -> uint8;
|
||||
auto algorithmBIT(uint8) -> uint8;
|
||||
auto algorithmCMP(uint8) -> uint8;
|
||||
auto algorithmCPX(uint8) -> uint8;
|
||||
auto algorithmCPY(uint8) -> uint8;
|
||||
auto algorithmDEC(uint8) -> uint8;
|
||||
auto algorithmEOR(uint8) -> uint8;
|
||||
auto algorithmINC(uint8) -> uint8;
|
||||
auto algorithmLD (uint8) -> uint8;
|
||||
auto algorithmLSR(uint8) -> uint8;
|
||||
auto algorithmORA(uint8) -> uint8;
|
||||
auto algorithmROL(uint8) -> uint8;
|
||||
auto algorithmROR(uint8) -> uint8;
|
||||
auto algorithmSBC(uint8) -> uint8;
|
||||
auto algorithmTRB(uint8) -> uint8;
|
||||
auto algorithmTSB(uint8) -> uint8;
|
||||
|
||||
using bp = auto (HuC6280::*)(uint16&, uint16&, bool) -> void;
|
||||
auto algorithmTAI(uint16&, uint16&, bool) -> void;
|
||||
auto algorithmTDD(uint16&, uint16&, bool) -> void;
|
||||
auto algorithmTIA(uint16&, uint16&, bool) -> void;
|
||||
auto algorithmTII(uint16&, uint16&, bool) -> void;
|
||||
auto algorithmTIN(uint16&, uint16&, bool) -> void;
|
||||
|
||||
//instruction.cpp
|
||||
auto interrupt(uint16 vector) -> void;
|
||||
auto instruction() -> void;
|
||||
|
||||
//instructions.cpp
|
||||
auto instructionAbsoluteModify(fp, uint8 = 0) -> void;
|
||||
auto instructionAbsoluteRead(fp, uint8&, uint8 = 0) -> void;
|
||||
auto instructionAbsoluteReadMemory(fp, uint8 = 0) -> void;
|
||||
auto instructionAbsoluteWrite(uint8, uint8 = 0) -> void;
|
||||
auto instructionBlockMove(bp) -> void;
|
||||
auto instructionBranch(bool) -> void;
|
||||
auto instructionBranchIfBitReset(uint3) -> void;
|
||||
auto instructionBranchIfBitSet(uint3) -> void;
|
||||
auto instructionBranchSubroutine() -> void;
|
||||
auto instructionBreak() -> void;
|
||||
auto instructionCallAbsolute() -> void;
|
||||
auto instructionChangeSpeedLow() -> void;
|
||||
auto instructionChangeSpeedHigh() -> void;
|
||||
auto instructionClear(uint8&) -> void;
|
||||
auto instructionClear(bool&) -> void;
|
||||
auto instructionImmediate(fp, uint8&) -> void;
|
||||
auto instructionImmediateMemory(fp) -> void;
|
||||
auto instructionImplied(fp, uint8&) -> void;
|
||||
auto instructionIndirectRead(fp, uint8&, uint8 = 0) -> void;
|
||||
auto instructionIndirectReadMemory(fp, uint8 = 0) -> void;
|
||||
auto instructionIndirectWrite(uint8, uint8 = 0) -> void;
|
||||
auto instructionIndirectYRead(fp, uint8&) -> void;
|
||||
auto instructionIndirectYReadMemory(fp) -> void;
|
||||
auto instructionIndirectYWrite(uint8) -> void;
|
||||
auto instructionJumpAbsolute() -> void;
|
||||
auto instructionJumpIndirect(uint8 = 0) -> void;
|
||||
auto instructionNoOperation() -> void;
|
||||
auto instructionPull(uint8&) -> void;
|
||||
auto instructionPullP() -> void;
|
||||
auto instructionPush(uint8) -> void;
|
||||
auto instructionResetMemoryBit(uint3) -> void;
|
||||
auto instructionReturnInterrupt() -> void;
|
||||
auto instructionReturnSubroutine() -> void;
|
||||
auto instructionSet(bool&) -> void;
|
||||
auto instructionSetMemoryBit(uint3) -> void;
|
||||
auto instructionStoreImplied(uint2) -> void;
|
||||
auto instructionSwap(uint8&, uint8&) -> void;
|
||||
auto instructionTestAbsolute(uint8 = 0) -> void;
|
||||
auto instructionTestZeroPage(uint8 = 0) -> void;
|
||||
auto instructionTransfer(uint8&, uint8&) -> void;
|
||||
auto instructionTransferAccumulatorToMPR() -> void;
|
||||
auto instructionTransferMPRToAccumulator() -> void;
|
||||
auto instructionTransferXS() -> void;
|
||||
auto instructionZeroPageModify(fp, uint8 = 0) -> void;
|
||||
auto instructionZeroPageRead(fp, uint8&, uint8 = 0) -> void;
|
||||
auto instructionZeroPageReadMemory(fp, uint8 = 0) -> void;
|
||||
auto instructionZeroPageWrite(uint8, uint8 = 0) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassembleInstruction() -> string;
|
||||
auto disassembleContext() -> string;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Flags {
|
||||
bool c; //carry
|
||||
bool z; //zero
|
||||
bool i; //interrupt disable
|
||||
bool d; //decimal mode
|
||||
bool b; //break
|
||||
bool t; //memory operation
|
||||
bool v; //overflow
|
||||
bool n; //negative
|
||||
|
||||
inline operator uint8() const {
|
||||
return c << 0 | z << 1 | i << 2 | d << 3 | b << 4 | t << 5 | v << 6 | n << 7;
|
||||
}
|
||||
|
||||
inline auto operator()() const -> uint8 {
|
||||
return operator uint8();
|
||||
}
|
||||
|
||||
inline auto& operator=(uint8 data) {
|
||||
c = data.bit(0);
|
||||
z = data.bit(1);
|
||||
i = data.bit(2);
|
||||
d = data.bit(3);
|
||||
b = data.bit(4);
|
||||
t = data.bit(5);
|
||||
v = data.bit(6);
|
||||
n = data.bit(7);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct Registers {
|
||||
uint8 a;
|
||||
uint8 x;
|
||||
uint8 y;
|
||||
uint8 s;
|
||||
uint16 pc;
|
||||
uint8 mpr[8];
|
||||
uint8 mpl; //MPR latch
|
||||
uint8 cs; //code speed (3 = fast, 12 = slow)
|
||||
Flags p;
|
||||
} r;
|
||||
|
||||
bool blockMove;
|
||||
Random random;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
||||
#define fp(name) &HuC6280::algorithm##name
|
||||
|
||||
auto HuC6280::interrupt(uint16 vector) -> void {
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
push(PC >> 8);
|
||||
push(PC >> 0);
|
||||
push(P() & ~0x10); //B flag is clear
|
||||
I = 1;
|
||||
D = 0;
|
||||
T = 0;
|
||||
PC.byte(0) = load16(vector + 0);
|
||||
L PC.byte(1) = load16(vector + 1);
|
||||
}
|
||||
|
||||
auto HuC6280::instruction() -> void {
|
||||
auto code = opcode();
|
||||
|
||||
if(T) {
|
||||
T = 0;
|
||||
switch(code) {
|
||||
op(0x01, IndirectReadMemory, fp(ORA), X)
|
||||
op(0x05, ZeroPageReadMemory, fp(ORA))
|
||||
op(0x09, ImmediateMemory, fp(ORA))
|
||||
op(0x0d, AbsoluteReadMemory, fp(ORA))
|
||||
op(0x11, IndirectYReadMemory, fp(ORA))
|
||||
op(0x12, IndirectReadMemory, fp(ORA))
|
||||
op(0x15, ZeroPageReadMemory, fp(ORA), X)
|
||||
op(0x19, AbsoluteReadMemory, fp(ORA), Y)
|
||||
op(0x1d, AbsoluteReadMemory, fp(ORA), X)
|
||||
|
||||
op(0x21, IndirectReadMemory, fp(AND), X)
|
||||
op(0x25, ZeroPageReadMemory, fp(AND))
|
||||
op(0x29, ImmediateMemory, fp(AND))
|
||||
op(0x2d, AbsoluteReadMemory, fp(AND))
|
||||
op(0x31, IndirectYReadMemory, fp(AND))
|
||||
op(0x32, IndirectReadMemory, fp(AND))
|
||||
op(0x35, ZeroPageReadMemory, fp(AND), X)
|
||||
op(0x39, AbsoluteReadMemory, fp(AND), Y)
|
||||
op(0x3d, AbsoluteReadMemory, fp(AND), X)
|
||||
|
||||
op(0x41, IndirectReadMemory, fp(EOR), X)
|
||||
op(0x45, ZeroPageReadMemory, fp(EOR))
|
||||
op(0x49, ImmediateMemory, fp(EOR))
|
||||
op(0x4d, AbsoluteReadMemory, fp(EOR))
|
||||
op(0x51, IndirectYReadMemory, fp(EOR))
|
||||
op(0x52, IndirectReadMemory, fp(EOR))
|
||||
op(0x55, ZeroPageReadMemory, fp(EOR), X)
|
||||
op(0x59, AbsoluteReadMemory, fp(EOR), Y)
|
||||
op(0x5d, AbsoluteReadMemory, fp(EOR), X)
|
||||
|
||||
op(0x61, IndirectReadMemory, fp(ADC), X)
|
||||
op(0x65, ZeroPageReadMemory, fp(ADC))
|
||||
op(0x69, ImmediateMemory, fp(ADC))
|
||||
op(0x6d, AbsoluteReadMemory, fp(ADC))
|
||||
op(0x71, IndirectYReadMemory, fp(ADC))
|
||||
op(0x72, IndirectReadMemory, fp(ADC))
|
||||
op(0x75, ZeroPageReadMemory, fp(ADC), X)
|
||||
op(0x79, AbsoluteReadMemory, fp(ADC), Y)
|
||||
op(0x7d, AbsoluteReadMemory, fp(ADC), X)
|
||||
}
|
||||
}
|
||||
|
||||
#define U
|
||||
switch(code) {
|
||||
op(0x00, Break)
|
||||
op(0x01, IndirectRead, fp(ORA), A, X)
|
||||
op(0x02, Swap, X, Y)
|
||||
op(0x03, StoreImplied, 0)
|
||||
op(0x04, ZeroPageModify, fp(TSB))
|
||||
op(0x05, ZeroPageRead, fp(ORA), A)
|
||||
op(0x06, ZeroPageModify, fp(ASL))
|
||||
op(0x07, ResetMemoryBit, 0)
|
||||
op(0x08, Push, P)
|
||||
op(0x09, Immediate, fp(ORA), A)
|
||||
op(0x0a, Implied, fp(ASL), A)
|
||||
U op(0x0b, NoOperation)
|
||||
op(0x0c, AbsoluteModify, fp(TSB))
|
||||
op(0x0d, AbsoluteRead, fp(ORA), A)
|
||||
op(0x0e, AbsoluteModify, fp(ASL))
|
||||
op(0x0f, BranchIfBitReset, 0)
|
||||
op(0x10, Branch, N == 0)
|
||||
op(0x11, IndirectYRead, fp(ORA), A)
|
||||
op(0x12, IndirectRead, fp(ORA), A)
|
||||
op(0x13, StoreImplied, 1)
|
||||
op(0x14, ZeroPageModify, fp(TRB))
|
||||
op(0x15, ZeroPageRead, fp(ORA), A, X)
|
||||
op(0x16, ZeroPageModify, fp(ASL), X)
|
||||
op(0x17, ResetMemoryBit, 1)
|
||||
op(0x18, Clear, C)
|
||||
op(0x19, AbsoluteRead, fp(ORA), A, Y)
|
||||
op(0x1a, Implied, fp(INC), A)
|
||||
U op(0x1b, NoOperation)
|
||||
op(0x1c, AbsoluteModify, fp(TRB))
|
||||
op(0x1d, AbsoluteRead, fp(ORA), A, X)
|
||||
op(0x1e, AbsoluteModify, fp(ASL), X)
|
||||
op(0x1f, BranchIfBitReset, 1)
|
||||
op(0x20, CallAbsolute)
|
||||
op(0x21, IndirectRead, fp(AND), A, X)
|
||||
op(0x22, Swap, A, X)
|
||||
op(0x23, StoreImplied, 2)
|
||||
op(0x24, ZeroPageRead, fp(BIT), A)
|
||||
op(0x25, ZeroPageRead, fp(AND), A)
|
||||
op(0x26, ZeroPageModify, fp(ROL))
|
||||
op(0x27, ResetMemoryBit, 2)
|
||||
op(0x28, PullP)
|
||||
op(0x29, Immediate, fp(AND), A)
|
||||
op(0x2a, Implied, fp(ROL), A)
|
||||
U op(0x2b, NoOperation)
|
||||
op(0x2c, AbsoluteRead, fp(BIT), A)
|
||||
op(0x2d, AbsoluteRead, fp(AND), A)
|
||||
op(0x2e, AbsoluteModify, fp(ROL))
|
||||
op(0x2f, BranchIfBitReset, 2)
|
||||
op(0x30, Branch, N == 1)
|
||||
op(0x31, IndirectYRead, fp(AND), A)
|
||||
op(0x32, IndirectRead, fp(AND), A)
|
||||
U op(0x33, NoOperation)
|
||||
op(0x34, ZeroPageRead, fp(BIT), A, X)
|
||||
op(0x35, ZeroPageRead, fp(AND), A, X)
|
||||
op(0x36, ZeroPageModify, fp(ROL), X)
|
||||
op(0x37, ResetMemoryBit, 3)
|
||||
op(0x38, Set, C)
|
||||
op(0x39, AbsoluteRead, fp(AND), A, Y)
|
||||
op(0x3a, Implied, fp(DEC), A)
|
||||
U op(0x3b, NoOperation)
|
||||
op(0x3c, AbsoluteRead, fp(BIT), A, X)
|
||||
op(0x3d, AbsoluteRead, fp(AND), A, X)
|
||||
op(0x3e, AbsoluteModify, fp(ROL), X)
|
||||
op(0x3f, BranchIfBitReset, 3)
|
||||
op(0x40, ReturnInterrupt)
|
||||
op(0x41, IndirectRead, fp(EOR), A, X)
|
||||
op(0x42, Swap, A, Y)
|
||||
op(0x43, TransferMPRToAccumulator)
|
||||
op(0x44, BranchSubroutine)
|
||||
op(0x45, ZeroPageRead, fp(EOR), A)
|
||||
op(0x46, ZeroPageModify, fp(LSR))
|
||||
op(0x47, ResetMemoryBit, 4)
|
||||
op(0x48, Push, A)
|
||||
op(0x49, Immediate, fp(EOR), A)
|
||||
op(0x4a, Implied, fp(LSR), A)
|
||||
U op(0x4b, NoOperation)
|
||||
op(0x4c, JumpAbsolute)
|
||||
op(0x4d, AbsoluteRead, fp(EOR), A)
|
||||
op(0x4e, AbsoluteModify, fp(LSR))
|
||||
op(0x4f, BranchIfBitReset, 4)
|
||||
op(0x50, Branch, V == 0)
|
||||
op(0x51, IndirectYRead, fp(EOR), A)
|
||||
op(0x52, IndirectRead, fp(EOR), A)
|
||||
op(0x53, TransferAccumulatorToMPR)
|
||||
op(0x54, ChangeSpeedLow)
|
||||
op(0x55, ZeroPageRead, fp(EOR), A, X)
|
||||
op(0x56, ZeroPageModify, fp(LSR), X)
|
||||
op(0x57, ResetMemoryBit, 5)
|
||||
op(0x58, Clear, I)
|
||||
op(0x59, AbsoluteRead, fp(EOR), A, Y)
|
||||
op(0x5a, Push, Y)
|
||||
U op(0x5b, NoOperation)
|
||||
U op(0x5c, NoOperation)
|
||||
op(0x5d, AbsoluteRead, fp(EOR), A, X)
|
||||
op(0x5e, AbsoluteModify, fp(LSR), X)
|
||||
op(0x5f, BranchIfBitReset, 5)
|
||||
op(0x60, ReturnSubroutine)
|
||||
op(0x61, IndirectRead, fp(ADC), A, X)
|
||||
op(0x62, Clear, A)
|
||||
U op(0x63, NoOperation)
|
||||
op(0x64, ZeroPageWrite, 0)
|
||||
op(0x65, ZeroPageRead, fp(ADC), A)
|
||||
op(0x66, ZeroPageModify, fp(ROR))
|
||||
op(0x67, ResetMemoryBit, 6)
|
||||
op(0x68, Pull, A)
|
||||
op(0x69, Immediate, fp(ADC), A)
|
||||
op(0x6a, Implied, fp(ROR), A)
|
||||
U op(0x6b, NoOperation)
|
||||
op(0x6c, JumpIndirect)
|
||||
op(0x6d, AbsoluteRead, fp(ADC), A)
|
||||
op(0x6e, AbsoluteModify, fp(ROR))
|
||||
op(0x6f, BranchIfBitReset, 6)
|
||||
op(0x70, Branch, V == 1)
|
||||
op(0x71, IndirectYRead, fp(ADC), A)
|
||||
op(0x72, IndirectRead, fp(ADC), A)
|
||||
op(0x73, BlockMove, fp(TII))
|
||||
op(0x74, ZeroPageWrite, 0, X)
|
||||
op(0x75, ZeroPageRead, fp(ADC), A, X)
|
||||
op(0x76, ZeroPageModify, fp(ROR), X)
|
||||
op(0x77, ResetMemoryBit, 7)
|
||||
op(0x78, Set, I)
|
||||
op(0x79, AbsoluteRead, fp(ADC), A, Y)
|
||||
op(0x7a, Pull, Y)
|
||||
U op(0x7b, NoOperation)
|
||||
op(0x7c, JumpIndirect, X)
|
||||
op(0x7d, AbsoluteRead, fp(ADC), A, X)
|
||||
op(0x7e, AbsoluteModify, fp(ROR), X)
|
||||
op(0x7f, BranchIfBitReset, 7)
|
||||
op(0x80, Branch, 1)
|
||||
op(0x81, IndirectWrite, A, X)
|
||||
op(0x82, Clear, X)
|
||||
op(0x83, TestZeroPage)
|
||||
op(0x84, ZeroPageWrite, Y)
|
||||
op(0x85, ZeroPageWrite, A)
|
||||
op(0x86, ZeroPageWrite, X)
|
||||
op(0x87, SetMemoryBit, 0)
|
||||
op(0x88, Implied, fp(DEC), Y)
|
||||
op(0x89, Immediate, fp(BIT), A)
|
||||
op(0x8a, Transfer, X, A)
|
||||
U op(0x8b, NoOperation)
|
||||
op(0x8c, AbsoluteWrite, Y)
|
||||
op(0x8d, AbsoluteWrite, A)
|
||||
op(0x8e, AbsoluteWrite, X)
|
||||
op(0x8f, BranchIfBitSet, 0)
|
||||
op(0x90, Branch, C == 0)
|
||||
op(0x91, IndirectYWrite, A)
|
||||
op(0x92, IndirectWrite, A)
|
||||
op(0x93, TestAbsolute)
|
||||
op(0x94, ZeroPageWrite, Y, X)
|
||||
op(0x95, ZeroPageWrite, A, X)
|
||||
op(0x96, ZeroPageWrite, X, Y)
|
||||
op(0x97, SetMemoryBit, 1)
|
||||
op(0x98, Transfer, Y, A)
|
||||
op(0x99, AbsoluteWrite, A, Y)
|
||||
op(0x9a, TransferXS)
|
||||
U op(0x9b, NoOperation)
|
||||
op(0x9c, AbsoluteWrite, 0)
|
||||
op(0x9d, AbsoluteWrite, A, X)
|
||||
op(0x9e, AbsoluteWrite, 0, X)
|
||||
op(0x9f, BranchIfBitSet, 1)
|
||||
op(0xa0, Immediate, fp(LD), Y)
|
||||
op(0xa1, IndirectRead, fp(LD), A, X)
|
||||
op(0xa2, Immediate, fp(LD), X)
|
||||
op(0xa3, TestZeroPage, X)
|
||||
op(0xa4, ZeroPageRead, fp(LD), Y)
|
||||
op(0xa5, ZeroPageRead, fp(LD), A)
|
||||
op(0xa6, ZeroPageRead, fp(LD), X)
|
||||
op(0xa7, SetMemoryBit, 2)
|
||||
op(0xa8, Transfer, A, Y)
|
||||
op(0xa9, Immediate, fp(LD), A)
|
||||
op(0xaa, Transfer, A, X)
|
||||
U op(0xab, NoOperation)
|
||||
op(0xac, AbsoluteRead, fp(LD), Y)
|
||||
op(0xad, AbsoluteRead, fp(LD), A)
|
||||
op(0xae, AbsoluteRead, fp(LD), X)
|
||||
op(0xaf, BranchIfBitSet, 2)
|
||||
op(0xb0, Branch, C == 1)
|
||||
op(0xb1, IndirectYRead, fp(LD), A)
|
||||
op(0xb2, IndirectRead, fp(LD), A)
|
||||
op(0xb3, TestAbsolute, X)
|
||||
op(0xb4, ZeroPageRead, fp(LD), Y, X)
|
||||
op(0xb5, ZeroPageRead, fp(LD), A, X)
|
||||
op(0xb6, ZeroPageRead, fp(LD), X, Y)
|
||||
op(0xb7, SetMemoryBit, 3)
|
||||
op(0xb8, Clear, V)
|
||||
op(0xb9, AbsoluteRead, fp(LD), A, Y)
|
||||
op(0xba, Transfer, S, X)
|
||||
U op(0xbb, NoOperation)
|
||||
op(0xbc, AbsoluteRead, fp(LD), Y, X)
|
||||
op(0xbd, AbsoluteRead, fp(LD), A, X)
|
||||
op(0xbe, AbsoluteRead, fp(LD), X, Y)
|
||||
op(0xbf, BranchIfBitSet, 3)
|
||||
op(0xc0, Immediate, fp(CPY), Y)
|
||||
op(0xc1, IndirectRead, fp(CMP), A, X)
|
||||
op(0xc2, Clear, Y)
|
||||
op(0xc3, BlockMove, fp(TDD))
|
||||
op(0xc4, ZeroPageRead, fp(CPY), Y)
|
||||
op(0xc5, ZeroPageRead, fp(CMP), A)
|
||||
op(0xc6, ZeroPageModify, fp(DEC))
|
||||
op(0xc7, SetMemoryBit, 4)
|
||||
op(0xc8, Implied, fp(INC), Y)
|
||||
op(0xc9, Immediate, fp(CMP), A)
|
||||
op(0xca, Implied, fp(DEC), X)
|
||||
U op(0xcb, NoOperation)
|
||||
op(0xcc, AbsoluteRead, fp(CPY), Y)
|
||||
op(0xcd, AbsoluteRead, fp(CMP), A)
|
||||
op(0xce, AbsoluteModify, fp(DEC))
|
||||
op(0xcf, BranchIfBitSet, 4)
|
||||
op(0xd0, Branch, Z == 0)
|
||||
op(0xd1, IndirectYRead, fp(CMP), A)
|
||||
op(0xd2, IndirectRead, fp(CMP), A)
|
||||
op(0xd3, BlockMove, fp(TIN))
|
||||
op(0xd4, ChangeSpeedHigh)
|
||||
op(0xd5, ZeroPageRead, fp(CMP), A, X)
|
||||
op(0xd6, ZeroPageModify, fp(DEC), X)
|
||||
op(0xd7, SetMemoryBit, 5)
|
||||
op(0xd8, Clear, D)
|
||||
op(0xd9, AbsoluteRead, fp(CMP), A, Y)
|
||||
op(0xda, Push, X)
|
||||
U op(0xdb, NoOperation)
|
||||
U op(0xdc, NoOperation)
|
||||
op(0xdd, AbsoluteRead, fp(CMP), A, X)
|
||||
op(0xde, AbsoluteModify, fp(DEC), X)
|
||||
op(0xdf, BranchIfBitSet, 5)
|
||||
op(0xe0, Immediate, fp(CPX), X)
|
||||
op(0xe1, IndirectRead, fp(SBC), A, X)
|
||||
U op(0xe2, NoOperation)
|
||||
op(0xe3, BlockMove, fp(TIA))
|
||||
op(0xe4, ZeroPageRead, fp(CPX), X)
|
||||
op(0xe5, ZeroPageRead, fp(SBC), A)
|
||||
op(0xe6, ZeroPageModify, fp(INC))
|
||||
op(0xe7, SetMemoryBit, 6)
|
||||
op(0xe8, Implied, fp(INC), X)
|
||||
op(0xe9, Immediate, fp(SBC), A)
|
||||
op(0xea, NoOperation)
|
||||
U op(0xeb, NoOperation)
|
||||
op(0xec, AbsoluteRead, fp(CPX), X)
|
||||
op(0xed, AbsoluteRead, fp(SBC), A)
|
||||
op(0xee, AbsoluteModify, fp(INC))
|
||||
op(0xef, BranchIfBitSet, 6)
|
||||
op(0xf0, Branch, Z == 1)
|
||||
op(0xf1, IndirectYRead, fp(SBC), A)
|
||||
op(0xf2, IndirectRead, fp(SBC), A)
|
||||
op(0xf3, BlockMove, fp(TAI))
|
||||
op(0xf4, Set, T)
|
||||
op(0xf5, ZeroPageRead, fp(SBC), A, X)
|
||||
op(0xf6, ZeroPageModify, fp(INC), X)
|
||||
op(0xf7, SetMemoryBit, 7)
|
||||
op(0xf8, Set, D)
|
||||
op(0xf9, AbsoluteRead, fp(SBC), A, Y)
|
||||
op(0xfa, Pull, X)
|
||||
U op(0xfb, NoOperation)
|
||||
U op(0xfc, NoOperation)
|
||||
op(0xfd, AbsoluteRead, fp(SBC), A, X)
|
||||
op(0xfe, AbsoluteModify, fp(INC), X)
|
||||
op(0xff, BranchIfBitSet, 7)
|
||||
}
|
||||
#undef U
|
||||
}
|
||||
|
||||
#undef op
|
||||
#undef fp
|
||||
@@ -1,433 +0,0 @@
|
||||
auto HuC6280::instructionAbsoluteModify(fp alu, uint8 index) -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
idle();
|
||||
auto data = ALU(load16(absolute + index));
|
||||
L store16(absolute + index, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionAbsoluteRead(fp alu, uint8& data, uint8 index) -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
L data = ALU(load16(absolute + index));
|
||||
}
|
||||
|
||||
auto HuC6280::instructionAbsoluteReadMemory(fp alu, uint8 index) -> void {
|
||||
auto a = A;
|
||||
A = load8(X);
|
||||
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
A = ALU(load16(absolute + index));
|
||||
|
||||
L store8(X, A);
|
||||
A = a;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionAbsoluteWrite(uint8 data, uint8 index) -> void {
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
L store16(absolute + index, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBlockMove(bp alu) -> void {
|
||||
uint16 source = operand();
|
||||
source |= operand() << 8;
|
||||
uint16 target = operand();
|
||||
target |= operand() << 8;
|
||||
uint16 length = operand();
|
||||
length |= operand() << 8;
|
||||
push(Y);
|
||||
push(A);
|
||||
push(X);
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
blockMove = 1;
|
||||
bool alternate = 0;
|
||||
do {
|
||||
auto data = load16(source);
|
||||
store16(target, data);
|
||||
ALU(source, target, alternate);
|
||||
alternate ^= 1;
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
} while(--length);
|
||||
blockMove = 0;
|
||||
X = pull();
|
||||
A = pull();
|
||||
L Y = pull();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranch(bool take) -> void {
|
||||
if(!take) {
|
||||
L operand();
|
||||
} else {
|
||||
auto displacement = operand();
|
||||
idle();
|
||||
L idle();
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranchIfBitReset(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
auto displacement = operand();
|
||||
idle();
|
||||
idle();
|
||||
L auto data = load8(zeropage);
|
||||
if(data.bit(index) == 0) {
|
||||
idle();
|
||||
idle();
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranchIfBitSet(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
auto displacement = operand();
|
||||
idle();
|
||||
idle();
|
||||
L auto data = load8(zeropage);
|
||||
if(data.bit(index) == 1) {
|
||||
idle();
|
||||
idle();
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBranchSubroutine() -> void {
|
||||
auto displacement = operand();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
push(PC - 1 >> 8);
|
||||
L push(PC - 1 >> 0);
|
||||
PC += (int8)displacement;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionBreak() -> void {
|
||||
operand();
|
||||
idle();
|
||||
push(PC >> 8);
|
||||
push(PC >> 0);
|
||||
push(P() | 0x10); //B flag is set
|
||||
I = 1;
|
||||
D = 0;
|
||||
T = 0;
|
||||
PC.byte(0) = load16(0xfff6);
|
||||
L PC.byte(1) = load16(0xfff7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionCallAbsolute() -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
idle();
|
||||
idle();
|
||||
push(PC - 1 >> 8);
|
||||
L push(PC - 1 >> 0);
|
||||
PC = address;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionChangeSpeedLow() -> void {
|
||||
idle();
|
||||
CS = 12;
|
||||
L idle();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionChangeSpeedHigh() -> void {
|
||||
idle();
|
||||
CS = 3;
|
||||
L idle();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionClear(uint8& data) -> void {
|
||||
L idle();
|
||||
data = 0;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionClear(bool& flag) -> void {
|
||||
L idle();
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionImmediate(fp alu, uint8& data) -> void {
|
||||
L data = ALU(operand());
|
||||
}
|
||||
|
||||
auto HuC6280::instructionImmediateMemory(fp alu) -> void {
|
||||
auto a = A;
|
||||
A = load8(X);
|
||||
|
||||
A = ALU(operand());
|
||||
|
||||
L store8(X, A);
|
||||
A = a;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionImplied(fp alu, uint8& data) -> void {
|
||||
L idle();
|
||||
data = ALU(data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionIndirectRead(fp alu, uint8& data, uint8 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
uint16 absolute = load8(zeropage + index + 0);
|
||||
absolute |= load8(zeropage + index + 1) << 8;
|
||||
idle();
|
||||
L data = ALU(load16(absolute));
|
||||
}
|
||||
|
||||
auto HuC6280::instructionIndirectReadMemory(fp alu, uint8 index) -> void {
|
||||
auto a = A;
|
||||
A = load8(X);
|
||||
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
uint16 absolute = load8(zeropage + index + 0);
|
||||
absolute |= load8(zeropage + index + 1) << 8;
|
||||
idle();
|
||||
A = ALU(load16(absolute));
|
||||
|
||||
L store8(X, A);
|
||||
A = a;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionIndirectWrite(uint8 data, uint8 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
uint16 absolute = load8(zeropage + index + 0);
|
||||
absolute |= load8(zeropage + index + 1) << 8;
|
||||
idle();
|
||||
L store16(absolute, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionIndirectYRead(fp alu, uint8& data) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
uint16 absolute = load8(zeropage + 0);
|
||||
absolute |= load8(zeropage + 1) << 8;
|
||||
idle();
|
||||
L data = ALU(load16(absolute + Y));
|
||||
}
|
||||
|
||||
auto HuC6280::instructionIndirectYReadMemory(fp alu) -> void {
|
||||
auto a = A;
|
||||
A = load8(X);
|
||||
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
uint16 absolute = load8(zeropage + 0);
|
||||
absolute |= load8(zeropage + 1) << 8;
|
||||
idle();
|
||||
A = ALU(load16(absolute + Y));
|
||||
|
||||
L store8(X, A);
|
||||
A = a;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionIndirectYWrite(uint8 data) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
uint16 absolute = load8(zeropage + 0);
|
||||
absolute |= load8(zeropage + 1) << 8;
|
||||
idle();
|
||||
L store16(absolute + Y, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJumpAbsolute() -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
L idle();
|
||||
PC = address;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionJumpIndirect(uint8 index) -> void {
|
||||
uint16 address = operand();
|
||||
address |= operand() << 8;
|
||||
idle();
|
||||
idle();
|
||||
PC.byte(0) = load16(address + index + 0);
|
||||
L PC.byte(1) = load16(address + index + 1);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionNoOperation() -> void {
|
||||
L idle();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPull(uint8& data) -> void {
|
||||
idle();
|
||||
idle();
|
||||
L data = pull();
|
||||
Z = data == 0;
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPullP() -> void {
|
||||
idle();
|
||||
idle();
|
||||
L P = pull() | 0x10; //B flag is set
|
||||
}
|
||||
|
||||
auto HuC6280::instructionPush(uint8 data) -> void {
|
||||
idle();
|
||||
L push(data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionResetMemoryBit(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
auto data = load8(zeropage);
|
||||
data.bit(index) = 0;
|
||||
L store8(zeropage, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionReturnInterrupt() -> void {
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
P = pull();
|
||||
PC.byte(0) = pull();
|
||||
L PC.byte(1) = pull();
|
||||
}
|
||||
|
||||
auto HuC6280::instructionReturnSubroutine() -> void {
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
PC.byte(0) = pull();
|
||||
PC.byte(1) = pull();
|
||||
L idle();
|
||||
PC++;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSet(bool& flag) -> void {
|
||||
L idle();
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSetMemoryBit(uint3 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
auto data = load8(zeropage);
|
||||
data.bit(index) = 1;
|
||||
L store8(zeropage, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionStoreImplied(uint2 index) -> void {
|
||||
auto data = operand();
|
||||
idle();
|
||||
idle();
|
||||
L store(index, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionSwap(uint8& lhs, uint8& rhs) -> void {
|
||||
idle();
|
||||
L idle();
|
||||
swap(lhs, rhs);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTestAbsolute(uint8 index) -> void {
|
||||
auto mask = operand();
|
||||
uint16 absolute = operand();
|
||||
absolute |= operand() << 8;
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
L uint8 data = load16(absolute + index);
|
||||
Z = (data & mask) == 0;
|
||||
V = data.bit(6);
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTestZeroPage(uint8 index) -> void {
|
||||
auto mask = operand();
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
idle();
|
||||
idle();
|
||||
L uint8 data = load8(zeropage + index);
|
||||
Z = (data & mask) == 0;
|
||||
V = data.bit(6);
|
||||
N = data.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransfer(uint8& source, uint8& target) -> void {
|
||||
L idle();
|
||||
target = source;
|
||||
Z = target == 0;
|
||||
N = target.bit(7);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransferAccumulatorToMPR() -> void {
|
||||
auto mask = operand();
|
||||
idle();
|
||||
idle();
|
||||
L idle();
|
||||
for(uint index : range(8)) {
|
||||
if(mask.bit(index)) MPR[index] = MPL = A;
|
||||
}
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransferMPRToAccumulator() -> void {
|
||||
auto mask = operand();
|
||||
idle();
|
||||
L idle();
|
||||
if(mask) MPL = ~0;
|
||||
for(uint index : range(8)) {
|
||||
//exact logic if multiple bits are set is unknown; but it is combinatorial
|
||||
if(mask.bit(index)) MPL &= MPR[index];
|
||||
}
|
||||
//in the event no bits are set, A is loaded with the previously latched value
|
||||
A = MPL;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionTransferXS() -> void {
|
||||
L idle();
|
||||
S = X;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionZeroPageModify(fp alu, uint8 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
idle();
|
||||
auto data = ALU(load8(zeropage + index));
|
||||
L store8(zeropage + index, data);
|
||||
}
|
||||
|
||||
auto HuC6280::instructionZeroPageRead(fp alu, uint8& data, uint8 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
L data = ALU(load8(zeropage + index));
|
||||
}
|
||||
|
||||
auto HuC6280::instructionZeroPageReadMemory(fp alu, uint8 index) -> void {
|
||||
auto a = A;
|
||||
A = load8(X);
|
||||
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
A = ALU(load8(zeropage + index));
|
||||
|
||||
L store8(X, A);
|
||||
A = a;
|
||||
}
|
||||
|
||||
auto HuC6280::instructionZeroPageWrite(uint8 data, uint8 index) -> void {
|
||||
auto zeropage = operand();
|
||||
idle();
|
||||
L store8(zeropage + index, data);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
auto HuC6280::load8(uint8 address) -> uint8 {
|
||||
step(CS);
|
||||
return read(MPR[1], address);
|
||||
}
|
||||
|
||||
auto HuC6280::load16(uint16 address) -> uint8 {
|
||||
step(CS);
|
||||
return read(MPR[address >> 13], (uint13)address);
|
||||
}
|
||||
|
||||
auto HuC6280::store8(uint8 address, uint8 data) -> void {
|
||||
step(CS);
|
||||
return write(MPR[1], address, data);
|
||||
}
|
||||
|
||||
auto HuC6280::store16(uint16 address, uint8 data) -> void {
|
||||
step(CS);
|
||||
return write(MPR[address >> 13], (uint13)address, data);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto HuC6280::idle() -> void {
|
||||
step(CS);
|
||||
}
|
||||
|
||||
auto HuC6280::opcode() -> uint8 {
|
||||
return load16(PC++);
|
||||
}
|
||||
|
||||
auto HuC6280::operand() -> uint8 {
|
||||
return load16(PC++);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto HuC6280::push(uint8 data) -> void {
|
||||
step(CS);
|
||||
write(MPR[1], 0x0100 | S--, data);
|
||||
}
|
||||
|
||||
auto HuC6280::pull() -> uint8 {
|
||||
step(CS);
|
||||
return read(MPR[1], 0x0100 | ++S);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
auto HuC6280::serialize(serializer& s) -> void {
|
||||
s.integer(r.a);
|
||||
s.integer(r.x);
|
||||
s.integer(r.y);
|
||||
s.integer(r.s);
|
||||
s.integer(r.pc);
|
||||
s.array(r.mpr);
|
||||
s.integer(r.mpl);
|
||||
s.integer(r.cs);
|
||||
s.integer(r.p.c);
|
||||
s.integer(r.p.z);
|
||||
s.integer(r.p.i);
|
||||
s.integer(r.p.d);
|
||||
s.integer(r.p.b);
|
||||
s.integer(r.p.t);
|
||||
s.integer(r.p.v);
|
||||
s.integer(r.p.n);
|
||||
s.integer(blockMove);
|
||||
random.serialize(s);
|
||||
}
|
||||
Loaded 100 of 2543 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user