Compare commits
9 Commits
c2aef4f249
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a37caf8b2 | |||
| 3de2c63fe0 | |||
| 3856d81c47 | |||
| a621ec235a | |||
| f464dbfaf1 | |||
| 7d0b66f418 | |||
| 6e55faa2c0 | |||
| 952b79cf91 | |||
| 8ac0cbc57b |
@@ -1,6 +1,7 @@
|
|||||||
/target
|
/target
|
||||||
log
|
log
|
||||||
george.o
|
george.o
|
||||||
|
Cargo.lock
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.bin
|
*.bin
|
||||||
/result
|
/result
|
||||||
|
|||||||
Generated
-1075
File diff suppressed because it is too large
Load Diff
+19
-6
@@ -2,16 +2,29 @@
|
|||||||
name = "georgeemu"
|
name = "georgeemu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[[target.'cfg(not(target_arch = "wasm32"))'.bin]]
|
||||||
|
path = "src/bin/main.rs"
|
||||||
|
name = "george"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bdf-parser = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.81"
|
anyhow = "1.0.81"
|
||||||
bdf = "0.6.0"
|
minifb = { git = "https://github.com/emoon/rust_minifb" }
|
||||||
crossterm = "0.27.0"
|
|
||||||
minifb = "0.27.0"
|
|
||||||
# minifb = "0.25.0"
|
|
||||||
# ratatui = "0.26.3"
|
|
||||||
serde = { version = "1.0.197", features = ["serde_derive", "derive"] }
|
serde = { version = "1.0.197", features = ["serde_derive", "derive"] }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
console_error_panic_hook = "0.1.7"
|
||||||
|
web-sys = "0.3.70"
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
termion = "4.0.2"
|
termion = "4.0.2"
|
||||||
toml = "0.8.12"
|
toml = { version = "0.8.12" }
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::File,
|
||||||
|
io::{stdin, stdout, IsTerminal, Read, Write},
|
||||||
|
ops::Neg,
|
||||||
|
os::unix::process::CommandExt,
|
||||||
|
path::Path,
|
||||||
|
process::{exit, Command},
|
||||||
|
};
|
||||||
|
|
||||||
|
// takes all charaters in bdf and returns a vec of each character row byte in order, normalized to
|
||||||
|
// width & height of the font (only works with 8 or fewer pixel wide fonts, should work for any height)
|
||||||
|
fn bdf_to_bitmap(mut bdf: File) -> [u8; 0x8000] {
|
||||||
|
let mut bdf_font_bytes = Vec::new();
|
||||||
|
bdf.read_to_end(&mut bdf_font_bytes).unwrap();
|
||||||
|
|
||||||
|
let bdf_font = bdf_parser::BdfFont::parse(&bdf_font_bytes).unwrap();
|
||||||
|
let mut bdf_vec = vec![];
|
||||||
|
for glyph in bdf_font.glyphs.iter() {
|
||||||
|
let glyph_offset_x = glyph.bounding_box.offset.x;
|
||||||
|
let glyph_offset_y = glyph.bounding_box.offset.y;
|
||||||
|
let glyph_height = glyph.bounding_box.size.y;
|
||||||
|
let font_height = bdf_font.metadata.bounding_box.size.y;
|
||||||
|
let font_offset_y = bdf_font.metadata.bounding_box.offset.y;
|
||||||
|
|
||||||
|
let top_space = font_height + font_offset_y - glyph_height - glyph_offset_y;
|
||||||
|
for _ in 0..top_space {
|
||||||
|
bdf_vec.push(0x00);
|
||||||
|
}
|
||||||
|
for bitmap in glyph.bitmap.iter() {
|
||||||
|
bdf_vec.push(bitmap >> glyph_offset_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
let bottom_space = font_offset_y.neg() + glyph_offset_y;
|
||||||
|
for _ in 0..bottom_space {
|
||||||
|
bdf_vec.push(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let height = bdf_font.metadata.bounding_box.size.y as usize;
|
||||||
|
reorder_bitmap(&bdf_vec, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes an vec of ordered characters and translates them for use with the character rom
|
||||||
|
// TODO: make this work for any arbitrary char rom pin format using some kinda interface
|
||||||
|
fn reorder_bitmap(bitmap: &[u8], font_height: usize) -> [u8; 0x8000] {
|
||||||
|
let mut rom = [0; 0x8000]; // create vec the size of character rom
|
||||||
|
|
||||||
|
for row in 0..font_height {
|
||||||
|
for ascii_address in 0..u8::MAX {
|
||||||
|
// first 8 bits of address pick character
|
||||||
|
// next 5 bits pick row
|
||||||
|
// TODO: final 2 pick character set
|
||||||
|
let byte = bitmap[ascii_address as usize * font_height + row];
|
||||||
|
let rom_index: u16 = ((row as u16) << 8) + ascii_address as u16;
|
||||||
|
rom[rom_index as usize] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rom
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rom_from_file<P>(path: P) -> [u8; 0x8000]
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let file = File::open(path).unwrap();
|
||||||
|
bdf_to_bitmap(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut regen_font = Command::new("regen-font.sh");
|
||||||
|
let mut cleanup = Command::new("cleanup.sh");
|
||||||
|
|
||||||
|
regen_font.exec();
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let dest_path = Path::new(&out_dir).join("cozette.rom");
|
||||||
|
|
||||||
|
let cozette_rom_bytes = rom_from_file("build/cozette.bdf");
|
||||||
|
let mut cozette_rom = File::create(dest_path).unwrap();
|
||||||
|
cozette_rom.write_all(&cozette_rom_bytes).unwrap();
|
||||||
|
|
||||||
|
cleanup.exec();
|
||||||
|
}
|
||||||
+556
-549
File diff suppressed because it is too large
Load Diff
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
rm *.bdf*
|
||||||
File diff suppressed because it is too large
Load Diff
+3903
File diff suppressed because it is too large
Load Diff
+3903
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,523 @@
|
|||||||
|
# this is georgescii, august's version of extended ascii for george <3
|
||||||
|
# we're limited to 255 characters
|
||||||
|
# format: ascii byte, unicode hex, # unicode name
|
||||||
|
#
|
||||||
|
# format: three tab-separated columns
|
||||||
|
# column #1 is the ISO/IEC 8859-1 code (in hex as 0xXX)
|
||||||
|
# column #2 is the Unicode (in hex as 0xXXXX)
|
||||||
|
# column #3 the Unicode name (follows a comment sign, '#')
|
||||||
|
|
||||||
|
# 0x00 0x00 #
|
||||||
|
# 0x01 0x2591 # ░
|
||||||
|
# 0x02 0x2592 # ▒
|
||||||
|
# 0x03 0x2593 # ▓
|
||||||
|
# 0x04 0x2661 # ♡
|
||||||
|
# 0x05 0x2665 # ♥
|
||||||
|
# 0x06 0x2B50 # ⭐
|
||||||
|
# 0x07 0x272D # ✭
|
||||||
|
# 0x08 0xF005 #
|
||||||
|
# 0x09 0x2726 # ✦
|
||||||
|
# 0x0a 0x2728 # ✨
|
||||||
|
# 0x0b 0x2640 # ♀
|
||||||
|
# 0x0c 0x2642 # ♂
|
||||||
|
# 0x0d 0x26A2 # ⚢
|
||||||
|
# 0x0E 0x26A3 # ⚣
|
||||||
|
# 0x0F 0x26A5 # ⚥
|
||||||
|
# 0x10 0x2669 # ♩
|
||||||
|
# 0x11 0x266A # ♪
|
||||||
|
# 0x12 0x266B # ♫
|
||||||
|
# 0x13 0x266C # ♬
|
||||||
|
# 0x14 0xFC5D # ﱝ
|
||||||
|
# 0x15 0xF026 #
|
||||||
|
# 0x16 0xF027 #
|
||||||
|
# 0x17 0xF028 #
|
||||||
|
# 0x18 0xFA7E # 奄
|
||||||
|
# 0x19 0xFA7F # 奔
|
||||||
|
# 0x1A 0xFA80 # 婢
|
||||||
|
# 0x1B 0xFC5C # ﱜ
|
||||||
|
# 0x1C 0xFC5B # ﱛ
|
||||||
|
# 0x1D 0xF0AC #
|
||||||
|
# 0x1E 0xF04B #
|
||||||
|
# 0x1F 0xF04D #
|
||||||
|
# 0x20 0x0020 #
|
||||||
|
# 0x21 0x0021 # !
|
||||||
|
# 0x22 0x0022 # "
|
||||||
|
# 0x23 0x0023 # #
|
||||||
|
# 0x24 0x0024 # $
|
||||||
|
# 0x25 0x0025 # %
|
||||||
|
# 0x26 0x0026 # &
|
||||||
|
# 0x27 0x0027 # '
|
||||||
|
# 0x28 0x0028 # (
|
||||||
|
# 0x29 0x0029 # )
|
||||||
|
# 0x2A 0x002A # *
|
||||||
|
# 0x2B 0x002B # +
|
||||||
|
# 0x2C 0x002C # ,
|
||||||
|
# 0x2D 0x002D # -
|
||||||
|
# 0x2E 0x002E # .
|
||||||
|
# 0x2F 0x002F # /
|
||||||
|
# 0x30 0x0030 # 0
|
||||||
|
# 0x31 0x0031 # 1
|
||||||
|
# 0x32 0x0032 # 2
|
||||||
|
# 0x33 0x0033 # 3
|
||||||
|
# 0x34 0x0034 # 4
|
||||||
|
# 0x35 0x0035 # 5
|
||||||
|
# 0x36 0x0036 # 6
|
||||||
|
# 0x37 0x0037 # 7
|
||||||
|
# 0x38 0x0038 # 8
|
||||||
|
# 0x39 0x0039 # 9
|
||||||
|
# 0x3A 0x003A # :
|
||||||
|
# 0x3B 0x003B # ;
|
||||||
|
# 0x3C 0x003C # <
|
||||||
|
# 0x3D 0x003D # =
|
||||||
|
# 0x3E 0x003E # >
|
||||||
|
# 0x3F 0x003F # ?
|
||||||
|
# 0x40 0x0040 # @
|
||||||
|
# 0x41 0x0041 # A
|
||||||
|
# 0x42 0x0042 # B
|
||||||
|
# 0x43 0x0043 # C
|
||||||
|
# 0x44 0x0044 # D
|
||||||
|
# 0x45 0x0045 # E
|
||||||
|
# 0x46 0x0046 # F
|
||||||
|
# 0x47 0x0047 # G
|
||||||
|
# 0x48 0x0048 # H
|
||||||
|
# 0x49 0x0049 # I
|
||||||
|
# 0x4A 0x004A # J
|
||||||
|
# 0x4B 0x004B # K
|
||||||
|
# 0x4C 0x004C # L
|
||||||
|
# 0x4D 0x004D # M
|
||||||
|
# 0x4E 0x004E # N
|
||||||
|
# 0x4F 0x004F # O
|
||||||
|
# 0x50 0x0050 # P
|
||||||
|
# 0x51 0x0051 # Q
|
||||||
|
# 0x52 0x0052 # R
|
||||||
|
# 0x53 0x0053 # S
|
||||||
|
# 0x54 0x0054 # T
|
||||||
|
# 0x55 0x0055 # U
|
||||||
|
# 0x56 0x0056 # V
|
||||||
|
# 0x57 0x0057 # W
|
||||||
|
# 0x58 0x0058 # X
|
||||||
|
# 0x59 0x0059 # Y
|
||||||
|
# 0x5A 0x005A # Z
|
||||||
|
# 0x5B 0x005B # [
|
||||||
|
# 0x5C 0x005C # \
|
||||||
|
# 0x5D 0x005D # ]
|
||||||
|
# 0x5E 0x005E # ^
|
||||||
|
# 0x5F 0x005F # _
|
||||||
|
# 0x60 0x0060 # `
|
||||||
|
# 0x61 0x0061 # a
|
||||||
|
# 0x62 0x0062 # b
|
||||||
|
# 0x63 0x0063 # c
|
||||||
|
# 0x64 0x0064 # d
|
||||||
|
# 0x65 0x0065 # e
|
||||||
|
# 0x66 0x0066 # f
|
||||||
|
# 0x67 0x0067 # g
|
||||||
|
# 0x68 0x0068 # h
|
||||||
|
# 0x69 0x0069 # i
|
||||||
|
# 0x6A 0x006A # j
|
||||||
|
# 0x6B 0x006B # k
|
||||||
|
# 0x6C 0x006C # l
|
||||||
|
# 0x6D 0x006D # m
|
||||||
|
# 0x6E 0x006E # n
|
||||||
|
# 0x6F 0x006F # o
|
||||||
|
# 0x70 0x0070 # p
|
||||||
|
# 0x71 0x0071 # q
|
||||||
|
# 0x72 0x0072 # r
|
||||||
|
# 0x73 0x0073 # s
|
||||||
|
# 0x74 0x0074 # t
|
||||||
|
# 0x75 0x0075 # u
|
||||||
|
# 0x76 0x0076 # v
|
||||||
|
# 0x77 0x0077 # w
|
||||||
|
# 0x78 0x0078 # x
|
||||||
|
# 0x79 0x0079 # y
|
||||||
|
# 0x7A 0x007A # z
|
||||||
|
# 0x7B 0x007B # {
|
||||||
|
# 0x7C 0x007C # |
|
||||||
|
# 0x7D 0x007D # }
|
||||||
|
# 0x7E 0x007E # ~
|
||||||
|
# 0x7F 0x2500 # ─
|
||||||
|
# 0x80 0x2502 # │
|
||||||
|
# 0x81 0x250C # ┌
|
||||||
|
# 0x82 0x2514 # └
|
||||||
|
# 0x83 0x251C # ├
|
||||||
|
# 0x84 0x2524 # ┤
|
||||||
|
# 0x85 0x252C # ┬
|
||||||
|
# 0x86 0x2534 # ┴
|
||||||
|
# 0x87 0x253C # ┼
|
||||||
|
# 0x88 0x256D # ╭
|
||||||
|
# 0x89 0x256E # ╮
|
||||||
|
# 0x8A 0x256F # ╯
|
||||||
|
# 0x8B 0x2570 # ╰
|
||||||
|
# 0x8C 0x2571 # ╱
|
||||||
|
# 0x8D 0x2572 # ╲
|
||||||
|
# 0x8E 0x2573 # ╳
|
||||||
|
# 0x8F 0x2550 # ═
|
||||||
|
# 0x90 0x2551 # ║
|
||||||
|
# 0x91 0x2554 # ╔
|
||||||
|
# 0x92 0x2557 # ╗
|
||||||
|
# 0x93 0x255a # ╚
|
||||||
|
# 0x94 0x255D # ╝
|
||||||
|
# 0x95 0x2560 # ╠
|
||||||
|
# 0x96 0x2563 # ╣
|
||||||
|
# 0x97 0x2566 # ╦
|
||||||
|
# 0x98 0x2569 # ╩
|
||||||
|
# 0x99 0x256C # ╬
|
||||||
|
# 0x9A 0xF04E #
|
||||||
|
# 0x9B 0xF050 #
|
||||||
|
# 0x9C 0xF051 #
|
||||||
|
# 0x9D 0xF052 #
|
||||||
|
# 0x9E 0xF048 #
|
||||||
|
# 0x9F 0xE0B0 #
|
||||||
|
# 0xA0 0xE0B2 #
|
||||||
|
# 0xA1 0xE0B4 #
|
||||||
|
# 0xA2 0xE0B6 #
|
||||||
|
# 0xA3 0xE0B8 #
|
||||||
|
# 0xA4 0xE0BA #
|
||||||
|
# 0xA5 0xE0BC #
|
||||||
|
# 0xA6 0xE0BE #
|
||||||
|
# 0xA7 0x2581 # ▁
|
||||||
|
# 0xA8 0x2582 # ▂
|
||||||
|
# 0xA9 0x2583 # ▃
|
||||||
|
# 0xAA 0x2584 # ▄
|
||||||
|
# 0xAB 0x2585 # ▅
|
||||||
|
# 0xAC 0x2586 # ▆
|
||||||
|
# 0xAD 0x2587 # ▇
|
||||||
|
# 0xAE 0x2588 # █
|
||||||
|
# 0xAF 0x2589 # ▉
|
||||||
|
# 0xB0 0x258A # ▊
|
||||||
|
# 0xB1 0x258B # ▋
|
||||||
|
# 0xB2 0x258C # ▌
|
||||||
|
# 0xB3 0x258D # ▍
|
||||||
|
# 0xB4 0x258E # ▎
|
||||||
|
# 0xB5 0x258F # ▏
|
||||||
|
# 0xB6 0x0295 # ʕ
|
||||||
|
# 0xB7 0x00B7 # ·
|
||||||
|
# 0xB8 0x1D25 # ᴥ
|
||||||
|
# 0xB9 0x0294 # ʔ
|
||||||
|
# 0xBA 0x2596 # ▖
|
||||||
|
# 0xBB 0x2597 # ▗
|
||||||
|
# 0xBC 0x2598 # ▘
|
||||||
|
# 0xBD 0x2599 # ▙
|
||||||
|
# 0xBE 0x259A # ▚
|
||||||
|
# 0xBF 0x259B # ▛
|
||||||
|
# 0xC0 0x259C # ▜
|
||||||
|
# 0xC1 0x259D # ▝
|
||||||
|
# 0xC2 0x259E # ▞
|
||||||
|
# 0xC3 0x259F # ▟
|
||||||
|
# 0xC4 0x2190 # ←
|
||||||
|
# 0xC5 0x2191 # ↑
|
||||||
|
# 0xC6 0x2192 # →
|
||||||
|
# 0xC7 0x2193 # ↓
|
||||||
|
# 0xC8 0x2B60 # ⭠
|
||||||
|
# 0xC9 0x2B61 # ⭡
|
||||||
|
# 0xCA 0x2B62 # ⭢
|
||||||
|
# 0xCB 0x2B63 # ⭣
|
||||||
|
# 0xCC 0x2B80 # ⮀
|
||||||
|
# 0xCD 0x2B81 # ⮁
|
||||||
|
# 0xCE 0x2B82 # ⮂
|
||||||
|
# 0xCF 0x2B83 # ⮃
|
||||||
|
# 0xD0 0xF049 #
|
||||||
|
# 0xD1 0xF04A #
|
||||||
|
# 0xD2 0x23F3 # ⏳
|
||||||
|
# 0xD3 0xF07B #
|
||||||
|
# 0xD4 0xF07C #
|
||||||
|
# 0xD5 0xF114 #
|
||||||
|
# 0xD6 0xF115 #
|
||||||
|
# 0xD7 0xF250 #
|
||||||
|
# 0xD8 0xF251 #
|
||||||
|
# 0xD9 0xF253 #
|
||||||
|
# 0xDA 0xF254 #
|
||||||
|
# 0xDB 0xF461 #
|
||||||
|
# 0xDC 0xF016 #
|
||||||
|
# 0xDD 0xF401 #
|
||||||
|
# 0xDE 0x1F52E # 🔮
|
||||||
|
# 0xDF 0xF2DB #
|
||||||
|
# 0xE0 0xF008 #
|
||||||
|
# 0xE1 0x25C7 # ◇
|
||||||
|
# 0xE2 0x25C8 # ◈
|
||||||
|
# 0xE3 0x1F311 # 🌑
|
||||||
|
# 0xE4 0x1F312 # 🌒
|
||||||
|
# 0xE5 0x1F313 # 🌓
|
||||||
|
# 0xE6 0x1F314 # 🌔
|
||||||
|
# 0xE7 0x1F315 # 🌕
|
||||||
|
# 0xE8 0x1F316 # 🌖
|
||||||
|
# 0xE9 0x1F317 # 🌗
|
||||||
|
# 0xEA 0x1F318 # 🌘
|
||||||
|
# 0xEB 0xF04C #
|
||||||
|
# 0xEC 0x2714 # ✔
|
||||||
|
# 0xED 0x2718 # ✘
|
||||||
|
# 0xEE 0x25C6 # ◆
|
||||||
|
# 0xEF 0xF15D #
|
||||||
|
# 0xF0 0xF15E #
|
||||||
|
# 0xF1 0xF071 #
|
||||||
|
# 0xF2 0xF449 #
|
||||||
|
# 0xF3 0xF529 #
|
||||||
|
# 0xF4 0xF658 #
|
||||||
|
# 0xF5 0xF659 #
|
||||||
|
# 0xF6 0x1f381 # 🎁
|
||||||
|
# 0xF7 0xf05a #
|
||||||
|
# 0xF8 0xf06a #
|
||||||
|
# 0xF9 0xf834 #
|
||||||
|
# 0xFA 0xf835 #
|
||||||
|
# 0xFB 0x2690 # ⚐
|
||||||
|
# 0xFC 0x2691 # ⚑
|
||||||
|
# 0xFD 0xf8d7 #
|
||||||
|
# 0xFE 0xf0e7 #
|
||||||
|
# 0xFF 0xf7d9 #
|
||||||
|
|
||||||
|
|
||||||
|
0x00 0x00 #
|
||||||
|
0x01 0x0295 # ʕ
|
||||||
|
0x02 0x00B7 # ·
|
||||||
|
0x03 0x1D25 # ᴥ
|
||||||
|
0x04 0x0294 # ʔ
|
||||||
|
0x05 0x2661 # ♡
|
||||||
|
0x06 0x2665 # ♥
|
||||||
|
0x07 0x2726 # ✦
|
||||||
|
0x08 0x25C7 # ◇
|
||||||
|
0x09 0x25C6 # ◆
|
||||||
|
0x0a 0x272D # ✭
|
||||||
|
0x0b 0xF005 #
|
||||||
|
0x0c 0x2728 # ✨
|
||||||
|
0x0d 0x000d # CR
|
||||||
|
0x0e 0x2518 # ┘
|
||||||
|
0x0f 0x2514 # └
|
||||||
|
0x10 0x250c # ┌
|
||||||
|
0x11 0x2510 # ┐
|
||||||
|
0x12 0x2500 # ─
|
||||||
|
0x13 0x2502 # │
|
||||||
|
0x14 0x2524 # ┤
|
||||||
|
0x15 0x2534 # ┴
|
||||||
|
0x16 0x251C # ├
|
||||||
|
0x17 0x252C # ┬
|
||||||
|
0x18 0x253C # ┼
|
||||||
|
0x19 0x2571 # ╱
|
||||||
|
0x1a 0x2572 # ╲
|
||||||
|
0x1b 0x2573 # ╳
|
||||||
|
0x1c 0x2591 # ░
|
||||||
|
0x1d 0x2592 # ▒
|
||||||
|
0x1e 0x2593 # ▓
|
||||||
|
0x1f 0x2588 # █
|
||||||
|
0x20 0x0020 #
|
||||||
|
0x21 0x0021 # !
|
||||||
|
0x22 0x0022 # "
|
||||||
|
0x23 0x0023 # #
|
||||||
|
0x24 0x0024 # $
|
||||||
|
0x25 0x0025 # %
|
||||||
|
0x26 0x0026 # &
|
||||||
|
0x27 0x0027 # '
|
||||||
|
0x28 0x0028 # (
|
||||||
|
0x29 0x0029 # )
|
||||||
|
0x2a 0x002A # *
|
||||||
|
0x2b 0x002B # +
|
||||||
|
0x2c 0x002C # ,
|
||||||
|
0x2d 0x002D # -
|
||||||
|
0x2e 0x002E # .
|
||||||
|
0x2f 0x002F # /
|
||||||
|
0x30 0x0030 # 0
|
||||||
|
0x31 0x0031 # 1
|
||||||
|
0x32 0x0032 # 2
|
||||||
|
0x33 0x0033 # 3
|
||||||
|
0x34 0x0034 # 4
|
||||||
|
0x35 0x0035 # 5
|
||||||
|
0x36 0x0036 # 6
|
||||||
|
0x37 0x0037 # 7
|
||||||
|
0x38 0x0038 # 8
|
||||||
|
0x39 0x0039 # 9
|
||||||
|
0x3a 0x003A # :
|
||||||
|
0x3b 0x003B # ;
|
||||||
|
0x3c 0x003C # <
|
||||||
|
0x3d 0x003D # =
|
||||||
|
0x3e 0x003E # >
|
||||||
|
0x3f 0x003F # ?
|
||||||
|
0x40 0x0040 # @
|
||||||
|
0x41 0x0041 # A
|
||||||
|
0x42 0x0042 # B
|
||||||
|
0x43 0x0043 # C
|
||||||
|
0x44 0x0044 # D
|
||||||
|
0x45 0x0045 # E
|
||||||
|
0x46 0x0046 # F
|
||||||
|
0x47 0x0047 # G
|
||||||
|
0x48 0x0048 # H
|
||||||
|
0x49 0x0049 # I
|
||||||
|
0x4a 0x004A # J
|
||||||
|
0x4b 0x004B # K
|
||||||
|
0x4c 0x004C # L
|
||||||
|
0x4d 0x004D # M
|
||||||
|
0x4e 0x004E # N
|
||||||
|
0x4f 0x004F # O
|
||||||
|
0x50 0x0050 # P
|
||||||
|
0x51 0x0051 # Q
|
||||||
|
0x52 0x0052 # R
|
||||||
|
0x53 0x0053 # S
|
||||||
|
0x54 0x0054 # T
|
||||||
|
0x55 0x0055 # U
|
||||||
|
0x56 0x0056 # V
|
||||||
|
0x57 0x0057 # W
|
||||||
|
0x58 0x0058 # X
|
||||||
|
0x59 0x0059 # Y
|
||||||
|
0x5a 0x005A # Z
|
||||||
|
0x5b 0x005B # [
|
||||||
|
0x5c 0x005C # \
|
||||||
|
0x5d 0x005D # ]
|
||||||
|
0x5e 0x005E # ^
|
||||||
|
0x5f 0x005F # _
|
||||||
|
0x60 0x0060 # `
|
||||||
|
0x61 0x0061 # a
|
||||||
|
0x62 0x0062 # b
|
||||||
|
0x63 0x0063 # c
|
||||||
|
0x64 0x0064 # d
|
||||||
|
0x65 0x0065 # e
|
||||||
|
0x66 0x0066 # f
|
||||||
|
0x67 0x0067 # g
|
||||||
|
0x68 0x0068 # h
|
||||||
|
0x69 0x0069 # i
|
||||||
|
0x6a 0x006A # j
|
||||||
|
0x6b 0x006B # k
|
||||||
|
0x6c 0x006C # l
|
||||||
|
0x6d 0x006D # m
|
||||||
|
0x6e 0x006E # n
|
||||||
|
0x6f 0x006F # o
|
||||||
|
0x70 0x0070 # p
|
||||||
|
0x71 0x0071 # q
|
||||||
|
0x72 0x0072 # r
|
||||||
|
0x73 0x0073 # s
|
||||||
|
0x74 0x0074 # t
|
||||||
|
0x75 0x0075 # u
|
||||||
|
0x76 0x0076 # v
|
||||||
|
0x77 0x0077 # w
|
||||||
|
0x78 0x0078 # x
|
||||||
|
0x79 0x0079 # y
|
||||||
|
0x7a 0x007A # z
|
||||||
|
0x7b 0x007B # {
|
||||||
|
0x7c 0x007C # |
|
||||||
|
0x7d 0x007D # }
|
||||||
|
0x7e 0x007E # ~
|
||||||
|
0x7f 0x256F # ╯
|
||||||
|
0x80 0x2570 # ╰
|
||||||
|
0x81 0x256D # ╭
|
||||||
|
0x82 0x256E # ╮
|
||||||
|
0x83 0x255D # ╝
|
||||||
|
0x84 0x255a # ╚
|
||||||
|
0x85 0x2554 # ╔
|
||||||
|
0x86 0x2557 # ╗
|
||||||
|
0x87 0x2550 # ═
|
||||||
|
0x88 0x2551 # ║
|
||||||
|
0x89 0x2563 # ╣
|
||||||
|
0x8a 0x2569 # ╩
|
||||||
|
0x8b 0x2560 # ╠
|
||||||
|
0x8c 0x2566 # ╦
|
||||||
|
0x8d 0x256C # ╬
|
||||||
|
0x8e 0xE0B8 #
|
||||||
|
0x8f 0xE0BA #
|
||||||
|
0x90 0xE0BC #
|
||||||
|
0x91 0xE0BE #
|
||||||
|
0x92 0xE0B2 #
|
||||||
|
0x93 0xE0B0 #
|
||||||
|
0x94 0xE0B6 #
|
||||||
|
0x95 0xE0B4 #
|
||||||
|
0x96 0x2596 # ▖
|
||||||
|
0x97 0x2597 # ▗
|
||||||
|
0x98 0x2598 # ▘
|
||||||
|
0x99 0x2599 # ▙
|
||||||
|
0x9a 0x259A # ▚
|
||||||
|
0x9b 0x259B # ▛
|
||||||
|
0x9c 0x259C # ▜
|
||||||
|
0x9d 0x259D # ▝
|
||||||
|
0x9e 0x259E # ▞
|
||||||
|
0x9f 0x259F # ▟
|
||||||
|
0xa0 0x2581 # ▁
|
||||||
|
0xa1 0x2582 # ▂
|
||||||
|
0xa2 0x2583 # ▃
|
||||||
|
0xa3 0x2584 # ▄
|
||||||
|
0xa4 0x2585 # ▅
|
||||||
|
0xa5 0x2586 # ▆
|
||||||
|
0xa6 0x2587 # ▇
|
||||||
|
0xa7 0x2589 # ▉
|
||||||
|
0xa8 0x258A # ▊
|
||||||
|
0xa9 0x258B # ▋
|
||||||
|
0xaa 0x258C # ▌
|
||||||
|
0xab 0x258D # ▍
|
||||||
|
0xac 0x258E # ▎
|
||||||
|
0xad 0x258F # ▏
|
||||||
|
0xae 0x1F311 # 🌑
|
||||||
|
0xaf 0x1F312 # 🌒
|
||||||
|
0xb0 0x1F313 # 🌓
|
||||||
|
0xb1 0x1F314 # 🌔
|
||||||
|
0xb2 0x1F315 # 🌕
|
||||||
|
0xb3 0x1F316 # 🌖
|
||||||
|
0xb4 0x1F317 # 🌗
|
||||||
|
0xb5 0x1F318 # 🌘
|
||||||
|
0xb6 0xF254 #
|
||||||
|
0xb7 0xF251 #
|
||||||
|
0xb8 0x23F3 # ⏳
|
||||||
|
0xb9 0xF253 #
|
||||||
|
0xba 0xF250 #
|
||||||
|
0xbb 0x2190 # ←
|
||||||
|
0xbc 0x2191 # ↑
|
||||||
|
0xbd 0x2192 # →
|
||||||
|
0xbe 0x2193 # ↓
|
||||||
|
0xbf 0x2B60 # ⭠
|
||||||
|
0xc0 0x2B61 # ⭡
|
||||||
|
0xc1 0x2B62 # ⭢
|
||||||
|
0xc2 0x2B63 # ⭣
|
||||||
|
0xc3 0x2B80 # ⮀
|
||||||
|
0xc4 0x2B81 # ⮁
|
||||||
|
0xc5 0x2B82 # ⮂
|
||||||
|
0xc6 0x2B83 # ⮃
|
||||||
|
0xc7 0xF049 #
|
||||||
|
0xc8 0xF04A #
|
||||||
|
0xc9 0xF048 #
|
||||||
|
0xca 0xF04B #
|
||||||
|
0xcb 0xF04C #
|
||||||
|
0xcc 0xF04D #
|
||||||
|
0xcd 0xF052 #
|
||||||
|
0xce 0xF051 #
|
||||||
|
0xcf 0xF04E #
|
||||||
|
0xd0 0xF050 #
|
||||||
|
0xd1 0xFC5D # ﱝ
|
||||||
|
0xd2 0xF026 #
|
||||||
|
0xd3 0xF027 #
|
||||||
|
0xd4 0xF028 #
|
||||||
|
0xd5 0xFA80 # 婢
|
||||||
|
0xd6 0xFC5C # ﱜ
|
||||||
|
0xd7 0xFC5B # ﱛ
|
||||||
|
0xd8 0x2669 # ♩
|
||||||
|
0xd9 0x266A # ♪
|
||||||
|
0xda 0x266B # ♫
|
||||||
|
0xdb 0x266C # ♬
|
||||||
|
0xdc 0xF016 #
|
||||||
|
0xdd 0xF07B #
|
||||||
|
0xde 0xF07C #
|
||||||
|
0xdf 0xF114 #
|
||||||
|
0xe0 0xF115 #
|
||||||
|
0xe1 0xF15D #
|
||||||
|
0xe2 0xF15E #
|
||||||
|
0xe3 0xF529 #
|
||||||
|
0xe4 0xF071 #
|
||||||
|
0xe5 0xF449 #
|
||||||
|
0xe6 0xf05a #
|
||||||
|
0xe7 0xF659 #
|
||||||
|
0xe8 0xF658 #
|
||||||
|
0xe9 0xf835 #
|
||||||
|
0xea 0xf834 #
|
||||||
|
0xeb 0x2690 # ⚐
|
||||||
|
0xec 0x2691 # ⚑
|
||||||
|
0xed 0xf7d9 #
|
||||||
|
0xee 0x2714 # ✔
|
||||||
|
0xef 0x2718 # ✘
|
||||||
|
0xf0 0xf0e7 #
|
||||||
|
0xf1 0xF2DB #
|
||||||
|
0xf2 0xF008 #
|
||||||
|
0xf3 0xF461 #
|
||||||
|
0xf4 0x2B50 # ⭐
|
||||||
|
0xf5 0xF401 #
|
||||||
|
0xf6 0x1F52E # 🔮
|
||||||
|
0xf7 0x1f381 # 🎁
|
||||||
|
0xf8 0xf8d7 #
|
||||||
|
0xf9 0xF0AC #
|
||||||
|
0xfa 0x25C8 # ◈
|
||||||
|
0xfb 0x2640 # ♀
|
||||||
|
0xfc 0x2642 # ♂
|
||||||
|
0xfd 0x26A2 # ⚢
|
||||||
|
0xfe 0x26A3 # ⚣
|
||||||
|
0xff 0x26A5 # ⚥
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
fontforge -lang=ff -c 'Open($1); LoadEncodingFile($2, "george"); Reencode("george"); Generate($3)' Cozette.sfd georgeencoding.txt cozette.bdf
|
||||||
|
sed -i'' -e 's/FONTBOUNDINGBOX 11 13 0 -3/FONTBOUNDINGBOX 8 13 0 -3/' *.bdf
|
||||||
|
mv cozette-13.bdf cozette.bdf
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
char_rom = "./src/roms/cozette.rom"
|
char_rom = "./src/roms/cozette.rom"
|
||||||
rom = "./src/roms/george.rom"
|
rom = "./src/roms/keyboard_sys.rom"
|
||||||
screen = "Window"
|
screen = "Window"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.org $00
|
||||||
|
|
||||||
|
.byte $80
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
bbr7 $00, reset
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
Binary file not shown.
Binary file not shown.
+238
@@ -0,0 +1,238 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
temp = $20 ; scratchpad page
|
||||||
|
|
||||||
|
cursor = $300
|
||||||
|
cursor_x = cursor
|
||||||
|
cursor_y = cursor + 1
|
||||||
|
|
||||||
|
rand_index = $200
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
init:
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
jsr print
|
||||||
|
jsr rand_draw
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
newline: ; sets cursor to start of next line
|
||||||
|
stz cursor_x
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
bne .end
|
||||||
|
stz cursor_y
|
||||||
|
rts
|
||||||
|
.end:
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
|
||||||
|
text:
|
||||||
|
.byte 1,2,3,2,4
|
||||||
|
.asciiz "- george loves u <3"
|
||||||
|
|
||||||
|
random_y:
|
||||||
|
.byte 25,12,0,20,4,25,5,13
|
||||||
|
.byte 20, 1, 1, 22, 12, 19, 19, 19
|
||||||
|
.byte 9, 0, 4, 18, 13, 14, 4, 16
|
||||||
|
.byte 8, 17, 21, 14, 23, 21, 9, 0
|
||||||
|
.byte 14, 10, 14, 2, 26, 18, 15, 23
|
||||||
|
.byte 12, 2, 5, 4, 25, 20, 27, 4
|
||||||
|
.byte 28, 21, 3, 22, 11, 25, 2, 25
|
||||||
|
.byte 13, 17, 17, 24, 8, 8, 20, 21
|
||||||
|
.byte 11, 24, 27, 25, 8, 12, 7, 0
|
||||||
|
.byte 27, 12, 19, 27, 10, 3, 19, 2
|
||||||
|
.byte 2, 23, 22, 5, 26, 28, 4, 16
|
||||||
|
.byte 18, 7, 10, 9, 6, 19, 9, 2
|
||||||
|
.byte 14, 8, 14, 18, 18, 2, 13, 0
|
||||||
|
.byte 15, 26, 3, 23, 17, 12, 18, 11
|
||||||
|
.byte 4, 16, 17, 22, 9, 25, 3, 15
|
||||||
|
.byte 28, 3, 6, 14, 25, 5, 21, 8
|
||||||
|
.byte 15, 18, 15, 5, 28, 6, 15, 4
|
||||||
|
.byte 10, 1, 16, 24, 6, 9, 22, 3
|
||||||
|
.byte 17, 18, 10, 19, 27, 11, 22, 16
|
||||||
|
.byte 22, 17, 15, 6, 23, 11, 11, 11
|
||||||
|
.byte 4, 15, 5, 25, 19, 1, 8, 26
|
||||||
|
.byte 21, 20, 17, 27, 11, 3, 11, 20
|
||||||
|
.byte 15, 28, 0, 6, 14, 23, 20, 21
|
||||||
|
.byte 17, 20, 16, 15, 19, 6, 21, 19
|
||||||
|
.byte 15, 27, 1, 22, 7, 0, 5, 2
|
||||||
|
.byte 14, 24, 15, 4, 20, 16, 1, 14
|
||||||
|
.byte 4, 16, 4, 8, 13, 26, 3, 9
|
||||||
|
.byte 12, 25, 5, 0, 7, 17, 14, 20
|
||||||
|
.byte 2, 26, 2, 27, 18, 23, 5, 8
|
||||||
|
.byte 4, 21, 10, 11, 28, 22, 6, 6
|
||||||
|
.byte 10, 13, 23, 12, 20, 28, 20, 1
|
||||||
|
.byte 27, 19, 25, 6, 1, 10, 1
|
||||||
|
|
||||||
|
random_x:
|
||||||
|
.byte 42, 59, 11, 5, 18, 0, 26, 1
|
||||||
|
.byte 61, 16, 1, 51, 36, 47, 23, 1
|
||||||
|
.byte 16, 50, 46, 4, 55, 31, 15, 2
|
||||||
|
.byte 45, 21, 59, 53, 15, 43, 0, 2
|
||||||
|
.byte 64, 31, 38, 41, 25, 12, 12, 3
|
||||||
|
.byte 30, 13, 64, 44, 21, 8, 48, 3
|
||||||
|
.byte 46, 1, 2, 33, 4, 32, 59, 28
|
||||||
|
.byte 4, 24, 58, 53, 21, 41, 30, 2
|
||||||
|
.byte 56, 53, 31, 10, 42, 12, 9, 54
|
||||||
|
.byte 14, 14, 24, 29, 43, 60, 54, 26
|
||||||
|
.byte 5, 53, 17, 55, 27, 46, 31, 3
|
||||||
|
.byte 26, 44, 63, 30, 10, 34, 62, 48
|
||||||
|
.byte 42, 47, 51, 7, 55, 32, 14, 21
|
||||||
|
.byte 15, 26, 52, 37, 48, 0, 13, 2
|
||||||
|
.byte 50, 20, 35, 32, 8, 41, 2, 24
|
||||||
|
.byte 18, 9, 52, 22, 52, 12, 19, 32
|
||||||
|
.byte 29, 46, 34, 58, 54, 51, 43, 57
|
||||||
|
.byte 62, 10, 12, 57, 36, 39, 4, 30
|
||||||
|
.byte 38, 9, 30, 32, 33, 57, 3, 25
|
||||||
|
.byte 21, 36, 59, 30, 19, 39, 9, 60
|
||||||
|
.byte 34, 50, 52, 37, 34, 42, 3, 33
|
||||||
|
.byte 40, 19, 2, 26, 10, 38, 46, 30
|
||||||
|
.byte 3, 1, 19, 16, 26, 58, 42, 49
|
||||||
|
.byte 63, 1, 63, 41, 0, 21, 41, 19
|
||||||
|
.byte 21, 45, 44, 52, 20, 5, 11, 64
|
||||||
|
.byte 1, 62, 16, 5, 5, 8, 58, 56
|
||||||
|
.byte 16, 26, 6, 37, 19, 16, 25, 29
|
||||||
|
.byte 64, 59, 16, 6, 41, 28, 8, 51
|
||||||
|
.byte 54, 5, 19, 28, 13, 38, 52, 35
|
||||||
|
.byte 42, 13, 34, 33, 61, 61, 7, 27
|
||||||
|
.byte 38, 33, 9, 57, 10, 30, 8, 4
|
||||||
|
.byte 46, 3, 39, 46, 62, 20, 48, 7
|
||||||
|
|
||||||
|
|
||||||
|
; increments the cursor line by line, looping to (0, 0) after (63, 28)
|
||||||
|
|
||||||
|
inc_cursor:
|
||||||
|
lda cursor_x
|
||||||
|
cmp #63
|
||||||
|
beq .newline
|
||||||
|
inc cursor_x
|
||||||
|
rts
|
||||||
|
.newline:
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
beq .newscreen
|
||||||
|
stz cursor_x
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
.newscreen:
|
||||||
|
stz cursor_y
|
||||||
|
stz cursor_x
|
||||||
|
rts
|
||||||
|
|
||||||
|
; zeroes out the display, resets cursor to 0,0
|
||||||
|
|
||||||
|
clear:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne .loop
|
||||||
|
stz cursor
|
||||||
|
stz cursor + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; prints string from cursor position, stopping at end of string or at 256 chars, whichever comes first
|
||||||
|
; $6000 + (64*Y) + X
|
||||||
|
; THIS WILL WRITE OUT OF BOUNDS IF THE CURSOR IS OUT OF BOUNDS/STRING IS TOO LONG
|
||||||
|
|
||||||
|
; TODO: figure out a simple way of writing arbitrary length strings
|
||||||
|
|
||||||
|
print:
|
||||||
|
jsr cursor_addr
|
||||||
|
ldy #0
|
||||||
|
; y_overflow = temp + 5
|
||||||
|
.loop:
|
||||||
|
lda text, y
|
||||||
|
beq .end
|
||||||
|
sta (temp), y
|
||||||
|
iny
|
||||||
|
bra .loop
|
||||||
|
.end:
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; calculates real vram address from cursor (x, y)
|
||||||
|
|
||||||
|
cursor_addr:
|
||||||
|
stz temp
|
||||||
|
stz temp + 1
|
||||||
|
lda cursor_y
|
||||||
|
beq .add_x ; if y's zero just add x
|
||||||
|
.y_mult:
|
||||||
|
; multiply by 64
|
||||||
|
clc
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
sta temp
|
||||||
|
.add_x:
|
||||||
|
clc
|
||||||
|
lda cursor_x
|
||||||
|
adc temp
|
||||||
|
sta temp
|
||||||
|
lda #0
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
clc
|
||||||
|
|
||||||
|
lda #$60
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
rand_draw:
|
||||||
|
ldx rand_index
|
||||||
|
lda random_x, x
|
||||||
|
sta cursor_x
|
||||||
|
lda random_y, x
|
||||||
|
sta cursor_y
|
||||||
|
jsr cursor_addr
|
||||||
|
inc rand_index
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
+189
@@ -0,0 +1,189 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
; okay so rn i wanna set up a very basic system init, and write a few subroutines to draw characters at x,y coordinates
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
key_row = $200 ; used for character lookup when key pressed
|
||||||
|
key_col = $201
|
||||||
|
cursor = $202
|
||||||
|
|
||||||
|
char_buffer = $300 ; 256 byte character buffer
|
||||||
|
|
||||||
|
kb_row = $4400 ; keyboard hardware register
|
||||||
|
kb_row_cache = $203 ; cache
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
cli
|
||||||
|
|
||||||
|
print_test:
|
||||||
|
lda #0
|
||||||
|
sta key_row
|
||||||
|
lda #5
|
||||||
|
sta key_col
|
||||||
|
push_coords #5, #5
|
||||||
|
|
||||||
|
main:
|
||||||
|
; jsr printtext
|
||||||
|
; key_zero:
|
||||||
|
; stz keyboard_cache, x
|
||||||
|
; dex
|
||||||
|
; bpl key_zero
|
||||||
|
; fim:
|
||||||
|
; cli
|
||||||
|
; bra fim
|
||||||
|
jsr print
|
||||||
|
; jsr print
|
||||||
|
stp
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; keyboard: ; reads keyboard registers and stores the column and row of the first key found
|
||||||
|
; ; TODO: make this routine store up to 8 indices (for 8 key rollover)
|
||||||
|
; ldy #0
|
||||||
|
; .check_row: ; loop through each row
|
||||||
|
; lda kb_row, y
|
||||||
|
; beq .skip_row ; if row has no key pressed, skip checking which key
|
||||||
|
; ; jmp key_down
|
||||||
|
; sta kb_row_cache, y ; if key pressed, cache it
|
||||||
|
; lda kb_row, y
|
||||||
|
; cmp kb_row_cache, y ; has key changed?
|
||||||
|
; beq key_down
|
||||||
|
; .skip_row:
|
||||||
|
; iny
|
||||||
|
; cpy #5
|
||||||
|
; bne .check_row
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; key_down: ; a is loaded with the row byte
|
||||||
|
; phy
|
||||||
|
; sty key_row ; store character row
|
||||||
|
; ldy #0
|
||||||
|
; .find_col: ; test each row bit, store column if key pressed
|
||||||
|
; lsr ; test bit 7
|
||||||
|
; bcs store_col ; if unset, don't go store character columnb
|
||||||
|
; .skip:
|
||||||
|
; iny
|
||||||
|
; cpy #8
|
||||||
|
; bne .find_col ; loop until we've checked each bit
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; store_col:
|
||||||
|
; sty key_col
|
||||||
|
; jsr print
|
||||||
|
; rts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print: ; x y -- prints the key indexed with key_col and key_row at position x, y
|
||||||
|
|
||||||
|
keymap_index:
|
||||||
|
push
|
||||||
|
lda key_col
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda #8
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda key_row
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
jsr mult
|
||||||
|
jsr plus
|
||||||
|
lda 0, x
|
||||||
|
tay
|
||||||
|
lda keymap, y
|
||||||
|
push
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
keymap:
|
||||||
|
.byte "?outrew?"
|
||||||
|
.byte "?piygsq?"
|
||||||
|
.byte "a??khvd?"
|
||||||
|
.byte "42ljbfz?"
|
||||||
|
.byte "31?mncx?"
|
||||||
|
.byte "????? m"
|
||||||
|
|
||||||
|
draw:
|
||||||
|
; push_coords #0, #0
|
||||||
|
; push_char #$00
|
||||||
|
; jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
lda 0, x ; load a with character to draw
|
||||||
|
pop ; and pop it off the stack
|
||||||
|
jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
rts
|
||||||
|
|
||||||
|
get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
;.byte 64
|
||||||
|
;.byte 0
|
||||||
|
pha
|
||||||
|
lda #64
|
||||||
|
push ; doing this instead until `push_lit` is fixed
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr mult ; multiply 64 with y (n2)
|
||||||
|
jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
;jsr push_lit ; push vram address onto the stack
|
||||||
|
;.byte $00
|
||||||
|
;.byte $60
|
||||||
|
lda #$60
|
||||||
|
push
|
||||||
|
sta 1, x
|
||||||
|
stz 0, x
|
||||||
|
jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr keyboard
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,215 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
temp = $20 ; scratchpad page
|
||||||
|
str_ptr = $30
|
||||||
|
|
||||||
|
cursor = $300
|
||||||
|
cursor_x = cursor
|
||||||
|
cursor_y = cursor + 1
|
||||||
|
|
||||||
|
char_buf = $302
|
||||||
|
char_buf_index = char_buf + 8
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
init:
|
||||||
|
lda #$31
|
||||||
|
sta str_ptr
|
||||||
|
lda #$80
|
||||||
|
sta str_ptr + 1
|
||||||
|
|
||||||
|
jsr clear
|
||||||
|
lda #0
|
||||||
|
sta cursor_x
|
||||||
|
lda #0
|
||||||
|
sta cursor_y
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
jsr print
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
newline: ; sets cursor to start of next line
|
||||||
|
stz cursor_x
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
bne .end
|
||||||
|
stz cursor_y
|
||||||
|
rts
|
||||||
|
.end:
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
|
||||||
|
text:
|
||||||
|
.asciiz "hello <3"
|
||||||
|
|
||||||
|
; increments the cursor line by line, looping to (0, 0) after (63, 28)
|
||||||
|
|
||||||
|
inc_cursor:
|
||||||
|
lda cursor_x
|
||||||
|
cmp #63
|
||||||
|
beq .newline
|
||||||
|
inc cursor_x
|
||||||
|
rts
|
||||||
|
.newline:
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
beq .newscreen
|
||||||
|
stz cursor_x
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
.newscreen:
|
||||||
|
stz cursor_y
|
||||||
|
stz cursor_x
|
||||||
|
rts
|
||||||
|
|
||||||
|
; zeroes out the display, resets cursor to 0,0
|
||||||
|
|
||||||
|
clear:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne .loop
|
||||||
|
stz cursor
|
||||||
|
stz cursor + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; prints string from cursor position, stopping at end of string or at 256 chars, whichever comes first
|
||||||
|
; $6000 + (64*Y) + X
|
||||||
|
; THIS WILL WRITE OUT OF BOUNDS IF THE CURSOR IS OUT OF BOUNDS/STRING IS TOO LONG
|
||||||
|
|
||||||
|
; TODO: figure out a simple way of writing arbitrary length strings
|
||||||
|
; and
|
||||||
|
|
||||||
|
print:
|
||||||
|
jsr cursor_addr
|
||||||
|
ldy #0
|
||||||
|
; y_overflow = temp + 5
|
||||||
|
.loop:
|
||||||
|
lda (str_ptr), y
|
||||||
|
beq .end
|
||||||
|
sta (temp), y
|
||||||
|
iny
|
||||||
|
bra .loop
|
||||||
|
.end:
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; calculates real vram address from cursor (x, y)
|
||||||
|
|
||||||
|
cursor_addr:
|
||||||
|
stz temp
|
||||||
|
stz temp + 1
|
||||||
|
lda cursor_y
|
||||||
|
beq .add_x ; if y's zero just add x
|
||||||
|
.y_mult:
|
||||||
|
; multiply by 64
|
||||||
|
clc
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
sta temp
|
||||||
|
.add_x:
|
||||||
|
clc
|
||||||
|
lda cursor_x
|
||||||
|
adc temp
|
||||||
|
sta temp
|
||||||
|
lda #0
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
clc
|
||||||
|
|
||||||
|
lda #$60
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; print_text:
|
||||||
|
; lda text,y
|
||||||
|
; beq .end
|
||||||
|
; sta $6000, y
|
||||||
|
; iny
|
||||||
|
; bra print_text
|
||||||
|
; .end:
|
||||||
|
; ldy #0
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
; lda 0, x ; load a with character to draw
|
||||||
|
; pop ; and pop it off the stack
|
||||||
|
; jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
; sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; ; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
; ;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
; ;.byte 64
|
||||||
|
; ;.byte 0
|
||||||
|
; pha
|
||||||
|
; lda #64
|
||||||
|
; push ; doing this instead until `push_lit` is fixed
|
||||||
|
; sta 0, x
|
||||||
|
; stz 1, x
|
||||||
|
; jsr mult ; multiply 64 with y (n2)
|
||||||
|
; jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
; ;jsr push_lit ; push vram address onto the stack
|
||||||
|
; ;.byte $00
|
||||||
|
; ;.byte $60
|
||||||
|
; lda #$60
|
||||||
|
; push
|
||||||
|
; sta 1, x
|
||||||
|
; stz 0, x
|
||||||
|
; jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
; pla
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
; jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
Binary file not shown.
+173
@@ -0,0 +1,173 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
; okay so rn i wanna set up a very basic system init, and write a few subroutines to draw characters at x,y coordinates
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
key_row = $200 ; used for character lookup when key pressed
|
||||||
|
key_col = $201
|
||||||
|
cursor = $202
|
||||||
|
|
||||||
|
char_buffer = $300 ; 256 byte character buffer
|
||||||
|
|
||||||
|
kb_row = $4400 ; keyboard hardware register
|
||||||
|
kb_row_cache = $203 ; cache
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #20
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
; jsr keyboard
|
||||||
|
; key_zero:
|
||||||
|
; stz keyboard_cache, x
|
||||||
|
; dex
|
||||||
|
; bpl key_zero
|
||||||
|
; fim:
|
||||||
|
; cli
|
||||||
|
; bra fim
|
||||||
|
; jsr kitty_keys
|
||||||
|
lda #9
|
||||||
|
sta $6000
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
not_keyboard:
|
||||||
|
ldy #0
|
||||||
|
.check_row: ; loop through each row
|
||||||
|
lda kb_row, y
|
||||||
|
beq .skip_row ; if row has no key pressed, skip checking which key
|
||||||
|
sta kb_row_cache, y ; if key pressed, cache it
|
||||||
|
lda kb_row, y
|
||||||
|
cmp kb_row_cache, y ; has key changed?
|
||||||
|
beq key_down
|
||||||
|
.skip_row:
|
||||||
|
iny
|
||||||
|
cpy #5
|
||||||
|
bne .check_row
|
||||||
|
rts
|
||||||
|
|
||||||
|
key_down: ; a is loaded with the row byte
|
||||||
|
phy
|
||||||
|
sty key_row ; store character row
|
||||||
|
ldy #0
|
||||||
|
.find_col: ; test each row bit, store column if key pressed
|
||||||
|
lsr ; test bit 7
|
||||||
|
bcs store_col ; if unset, don't go store character columnb
|
||||||
|
.skip:
|
||||||
|
iny
|
||||||
|
cpy #8
|
||||||
|
bne .find_col ; loop until we've checked each bit
|
||||||
|
|
||||||
|
store_col:
|
||||||
|
sty key_col
|
||||||
|
|
||||||
|
keymap_index:
|
||||||
|
push
|
||||||
|
lda key_col
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda #8
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda key_row
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
jsr mult
|
||||||
|
jsr plus
|
||||||
|
lda 0, x
|
||||||
|
tay
|
||||||
|
|
||||||
|
print: ; we've stored the character position, now let's
|
||||||
|
lda keymap, y
|
||||||
|
ldy cursor
|
||||||
|
sta $6000, y
|
||||||
|
inc cursor
|
||||||
|
ply
|
||||||
|
rts
|
||||||
|
|
||||||
|
keymap:
|
||||||
|
.byte "?outrew?"
|
||||||
|
.byte "?piygsq?"
|
||||||
|
.byte "a??khvd?"
|
||||||
|
.byte "42ljbfz?"
|
||||||
|
.byte "31?mncx?"
|
||||||
|
.byte "????? m"
|
||||||
|
|
||||||
|
; draw:
|
||||||
|
; ; push_coords #0, #0
|
||||||
|
; ; push_char #$00
|
||||||
|
; ; jsr draw_char
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
; lda 0, x ; load a with character to draw
|
||||||
|
; pop ; and pop it off the stack
|
||||||
|
; jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
; sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; ; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
; ;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
; ;.byte 64
|
||||||
|
; ;.byte 0
|
||||||
|
; pha
|
||||||
|
; lda #64
|
||||||
|
; push ; doing this instead until `push_lit` is fixed
|
||||||
|
; sta 0, x
|
||||||
|
; stz 1, x
|
||||||
|
; jsr mult ; multiply 64 with y (n2)
|
||||||
|
; jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
; ;jsr push_lit ; push vram address onto the stack
|
||||||
|
; ;.byte $00
|
||||||
|
; ;.byte $60
|
||||||
|
; lda #$60
|
||||||
|
; push
|
||||||
|
; sta 1, x
|
||||||
|
; stz 0, x
|
||||||
|
; jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
; pla
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
; jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
@@ -7,6 +7,6 @@ fi
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
vasm6502_oldstyle ./src/roms/$1.asm -dotdir -wdc02 -ldots -Fbin -o ./src/roms/$1.rom;
|
vasm6502_oldstyle roms/$1.asm -dotdir -wdc02 -ldots -Fbin -o roms/$1.rom;
|
||||||
cargo run -- rom "./src/roms/$1.rom";
|
cargo run -- rom "roms/$1.rom";
|
||||||
# hexdump -C ./cpu_dump.bin;
|
# hexdump -C ./cpu_dump.bin;
|
||||||
|
|||||||
@@ -7,7 +7,18 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::video::ScreenType;
|
#[derive(Serialize, Deserialize, Default, Debug)]
|
||||||
|
pub enum ScreenType {
|
||||||
|
Terminal,
|
||||||
|
#[default]
|
||||||
|
Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub rom: Option<String>,
|
||||||
|
pub screen: ScreenType,
|
||||||
|
pub char_rom: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct ConfigBuilder {
|
struct ConfigBuilder {
|
||||||
@@ -27,7 +38,7 @@ impl ConfigBuilder {
|
|||||||
|
|
||||||
fn build(self) -> Config {
|
fn build(self) -> Config {
|
||||||
let rom = match self.rom {
|
let rom = match self.rom {
|
||||||
Some(rom) => rom,
|
Some(rom) => Some(rom),
|
||||||
None => {
|
None => {
|
||||||
println!("no rom was provided :(");
|
println!("no rom was provided :(");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -44,12 +55,6 @@ impl ConfigBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Config {
|
|
||||||
pub rom: String,
|
|
||||||
pub screen: ScreenType,
|
|
||||||
pub char_rom: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn help(command: Option<String>) {
|
fn help(command: Option<String>) {
|
||||||
let executable: String = env::args().next().unwrap();
|
let executable: String = env::args().next().unwrap();
|
||||||
if let Some(command) = command {
|
if let Some(command) = command {
|
||||||
@@ -81,7 +86,11 @@ fn help(command: Option<String>) {
|
|||||||
println!(" rom, -r, --rom <path>: load a rom/binary from path");
|
println!(" rom, -r, --rom <path>: load a rom/binary from path");
|
||||||
println!(" screen, -s, --screen <type>: use the \"terminal\" or \"window\" display type");
|
println!(" screen, -s, --screen <type>: use the \"terminal\" or \"window\" display type");
|
||||||
println!("\nconfiguration:");
|
println!("\nconfiguration:");
|
||||||
println!(" george-emu searches for a `george.toml` in the current directory.\n in `george.toml` you can specify a path for the character rom using the key `char_rom` and the main rom/binary with the key `rom`");
|
println!(" george-emu searches for a `george.toml` in the current directory.\n in `george.toml` you can specify a path for the character rom\n using the key `char_rom` and the main rom/binary with the key `rom`");
|
||||||
|
println!("\ndebugging:");
|
||||||
|
println!(" you can pipe in a rom for george to evaluate.");
|
||||||
|
println!(" she'll read it until she reaches a breakpoint (`0x02`) or `stp` instruction,");
|
||||||
|
println!(" then will dump her memory to stdout <3");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,6 +110,7 @@ pub fn get_input() -> Config {
|
|||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("couldn't find a `george.toml` in the current directory!");
|
println!("couldn't find a `george.toml` in the current directory!");
|
||||||
|
println!("\nuse `{executable} --help` to see all config options");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
use std::io::{self, stdin, IsTerminal};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
mod cli;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use cli::get_input;
|
||||||
|
use georgeemu::memory::{Mem, MemHandle};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use georgeemu::GeorgeEmu;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use minifb::{Scale, ScaleMode, Window, WindowOptions};
|
||||||
|
|
||||||
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
use std::io::{stdout, Write};
|
||||||
|
|
||||||
|
use georgeemu::cpu::Cpu;
|
||||||
|
|
||||||
|
let mut input = stdin();
|
||||||
|
|
||||||
|
if !input.is_terminal() {
|
||||||
|
let mut bytes = [0u8; 0x8000];
|
||||||
|
input.read_exact(&mut bytes).unwrap();
|
||||||
|
let memory = make_memory(&bytes);
|
||||||
|
let mut cpu = Cpu::new(memory);
|
||||||
|
let final_output = cpu.run_to_end();
|
||||||
|
|
||||||
|
let _ = stdout().write_all(&final_output);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let window = Window::new(
|
||||||
|
"ʕ·ᴥ·ʔ-☆",
|
||||||
|
512,
|
||||||
|
380,
|
||||||
|
WindowOptions {
|
||||||
|
resize: true,
|
||||||
|
borderless: true,
|
||||||
|
title: true,
|
||||||
|
transparency: false,
|
||||||
|
scale: Scale::FitScreen,
|
||||||
|
scale_mode: ScaleMode::AspectRatioStretch,
|
||||||
|
topmost: false,
|
||||||
|
none: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let config = get_input();
|
||||||
|
let rom = match config.rom {
|
||||||
|
Some(path) => {
|
||||||
|
let mut file = File::open(path).unwrap();
|
||||||
|
let mut bin = vec![0; 0x8000];
|
||||||
|
file.read_exact(&mut bin).unwrap();
|
||||||
|
bin.try_into().unwrap()
|
||||||
|
}
|
||||||
|
None => *include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/roms/george.rom")),
|
||||||
|
};
|
||||||
|
let mut emu = GeorgeEmu::builder().rom(rom).window(window).build();
|
||||||
|
|
||||||
|
emu.run();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn make_memory(bytes: &[u8]) -> MemHandle {
|
||||||
|
let mut memory = Mem::new();
|
||||||
|
memory.load_bytes(bytes);
|
||||||
|
MemHandle::new(memory)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
fn main() {}
|
||||||
+56
-56
@@ -2,11 +2,11 @@ use crate::instructions::get_instruction;
|
|||||||
use crate::memory::{MemHandle, MemoryReader, MemoryWriter};
|
use crate::memory::{MemHandle, MemoryReader, MemoryWriter};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use termion::cursor::Goto;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum StatusFlag {
|
pub enum StatusFlag {
|
||||||
Negative = 0b1000_0000,
|
Negative = 0b1000_0000,
|
||||||
@@ -19,9 +19,10 @@ pub enum StatusFlag {
|
|||||||
Carry = 0b0000_0001,
|
Carry = 0b0000_0001,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CpuController(Sender<CpuControl>);
|
pub struct CpuController(Sender<CpuControl>);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum CpuControl {
|
pub enum CpuControl {
|
||||||
Irq,
|
Irq,
|
||||||
Nmi,
|
Nmi,
|
||||||
@@ -35,22 +36,23 @@ impl CpuController {
|
|||||||
Self(sender)
|
Self(sender)
|
||||||
}
|
}
|
||||||
pub fn irq(&self) {
|
pub fn irq(&self) {
|
||||||
self.0.send(CpuControl::Irq);
|
let _ = self.0.send(CpuControl::Irq);
|
||||||
}
|
}
|
||||||
pub fn nmi(&self) {
|
pub fn nmi(&self) {
|
||||||
self.0.send(CpuControl::Nmi);
|
let _ = self.0.send(CpuControl::Nmi);
|
||||||
}
|
}
|
||||||
pub fn toggle(&self) {
|
pub fn toggle(&self) {
|
||||||
self.0.send(CpuControl::Toggle);
|
let _ = self.0.send(CpuControl::Toggle);
|
||||||
}
|
}
|
||||||
pub fn cycle(&self) {
|
pub fn cycle(&self) {
|
||||||
self.0.send(CpuControl::Cycle);
|
let _ = self.0.send(CpuControl::Cycle);
|
||||||
}
|
}
|
||||||
pub fn data(&self) {
|
pub fn data(&self) {
|
||||||
self.0.send(CpuControl::Data);
|
let _ = self.0.send(CpuControl::Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct CpuReceiver(Receiver<CpuControl>);
|
pub struct CpuReceiver(Receiver<CpuControl>);
|
||||||
impl CpuReceiver {
|
impl CpuReceiver {
|
||||||
pub fn new(receiver: Receiver<CpuControl>) -> Self {
|
pub fn new(receiver: Receiver<CpuControl>) -> Self {
|
||||||
@@ -58,6 +60,7 @@ impl CpuReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Cpu {
|
pub struct Cpu {
|
||||||
pub a: u8, // Accumulator Register
|
pub a: u8, // Accumulator Register
|
||||||
pub x: u8, // X Register
|
pub x: u8, // X Register
|
||||||
@@ -69,10 +72,10 @@ pub struct Cpu {
|
|||||||
pub nmi: bool,
|
pub nmi: bool,
|
||||||
pub memory: MemHandle,
|
pub memory: MemHandle,
|
||||||
pub pending_cycles: usize,
|
pub pending_cycles: usize,
|
||||||
|
pub debug: bool,
|
||||||
receiver: Option<CpuReceiver>,
|
receiver: Option<CpuReceiver>,
|
||||||
stopped: bool,
|
stopped: bool,
|
||||||
cycle: bool, // cycle_count: usize,
|
cycle: bool,
|
||||||
// state_tx: Sender<CpuState>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Cpu {
|
impl Display for Cpu {
|
||||||
@@ -94,22 +97,28 @@ impl MemoryWriter for Cpu {
|
|||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub fn new(memory: MemHandle) -> Self {
|
pub fn new(memory: MemHandle) -> Self {
|
||||||
// pub fn new(memory: MemHandle) -> Self {
|
// reset the cpu on initialization so we don't
|
||||||
|
// scream and cry for two days trying to figure
|
||||||
|
// out why george isn't working <3
|
||||||
|
let low_byte = memory.read(0xFFFC);
|
||||||
|
let high_byte = memory.read(0xFFFD);
|
||||||
|
let pc = (high_byte as u16) << 8 | (low_byte as u16);
|
||||||
|
|
||||||
Cpu {
|
Cpu {
|
||||||
a: 0x00,
|
a: 0x00,
|
||||||
x: 0x00,
|
x: 0x00,
|
||||||
y: 0x00,
|
y: 0x00,
|
||||||
pc: 0x0000,
|
pc,
|
||||||
s: 0xFF,
|
s: 0xFF,
|
||||||
p: 0b0010_0100,
|
p: 0b0010_0100,
|
||||||
irq: false,
|
irq: false,
|
||||||
nmi: false,
|
nmi: false,
|
||||||
receiver: None,
|
receiver: None,
|
||||||
memory,
|
memory,
|
||||||
|
debug: false,
|
||||||
stopped: false,
|
stopped: false,
|
||||||
pending_cycles: 0,
|
pending_cycles: 0,
|
||||||
cycle: false, // cycle_count: 0,
|
cycle: false,
|
||||||
// state_tx,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self {
|
pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self {
|
||||||
@@ -179,13 +188,6 @@ impl Cpu {
|
|||||||
value & 0b1000_0000 == 0b1000_0000
|
value & 0b1000_0000 == 0b1000_0000
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn execute(&mut self) {
|
|
||||||
// self.cycle();
|
|
||||||
// while self.pending_cycles != 0 {
|
|
||||||
// self.cycle();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn wait_for_interrupt(&self) {
|
pub fn wait_for_interrupt(&self) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
@@ -198,6 +200,10 @@ impl Cpu {
|
|||||||
self.pc = self.read_word(0xFFFE);
|
self.pc = self.read_word(0xFFFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toggle_stopped(&mut self) {
|
||||||
|
self.stopped = !self.stopped;
|
||||||
|
}
|
||||||
|
|
||||||
fn receive_control(&mut self) {
|
fn receive_control(&mut self) {
|
||||||
match &self.receiver {
|
match &self.receiver {
|
||||||
Some(receiver) => {
|
Some(receiver) => {
|
||||||
@@ -213,7 +219,8 @@ impl Cpu {
|
|||||||
self.stopped = !self.stopped;
|
self.stopped = !self.stopped;
|
||||||
}
|
}
|
||||||
CpuControl::Cycle => self.cycle = true,
|
CpuControl::Cycle => self.cycle = true,
|
||||||
CpuControl::Data => {} // self
|
CpuControl::Data => {
|
||||||
|
// self
|
||||||
// .state_tx
|
// .state_tx
|
||||||
// .send(CpuState {
|
// .send(CpuState {
|
||||||
// a: self.a.clone(), // Accumulator Register
|
// a: self.a.clone(), // Accumulator Register
|
||||||
@@ -228,6 +235,7 @@ impl Cpu {
|
|||||||
// .unwrap(),
|
// .unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,6 +249,8 @@ impl Cpu {
|
|||||||
}
|
}
|
||||||
self.cycle = false;
|
self.cycle = false;
|
||||||
|
|
||||||
|
// can't sleep in wasm
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
while self.pending_cycles != 0 {
|
while self.pending_cycles != 0 {
|
||||||
// roughly cycle-accurate timing
|
// roughly cycle-accurate timing
|
||||||
sleep(Duration::from_nanos(500));
|
sleep(Duration::from_nanos(500));
|
||||||
@@ -252,45 +262,35 @@ impl Cpu {
|
|||||||
let opcode = self.read(self.pc);
|
let opcode = self.read(self.pc);
|
||||||
let instruction = get_instruction(opcode);
|
let instruction = get_instruction(opcode);
|
||||||
instruction.call(self);
|
instruction.call(self);
|
||||||
// println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi);
|
|
||||||
// println!(
|
|
||||||
// "Instruction: {:?}, {:#04x}",
|
|
||||||
// valid_instruction.opcode, opcode
|
|
||||||
// );
|
|
||||||
// println!("");
|
|
||||||
}
|
}
|
||||||
pub fn stop(&mut self) {
|
pub fn stop(&mut self) {
|
||||||
self.stopped = true;
|
self.stopped = true;
|
||||||
}
|
}
|
||||||
pub fn breakpoint(&mut self) {
|
pub fn breakpoint(&mut self) {
|
||||||
// println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi);
|
if self.debug {
|
||||||
// println!(
|
|
||||||
// "Instruction: {:?}, {:#04x}",
|
|
||||||
// valid_instruction.opcode, opcode
|
|
||||||
// );
|
|
||||||
// println!("");
|
|
||||||
// println!(
|
|
||||||
// "{}{:#04x}: {:#02x}, {:#04x}: {:#02x}",
|
|
||||||
// Goto(1, 35),
|
|
||||||
// 0x20,
|
|
||||||
// self.read(0x20),
|
|
||||||
// 0x21,
|
|
||||||
// self.read(0x21)
|
|
||||||
// );
|
|
||||||
// println!(
|
|
||||||
// "{}str_ptr {:#04x}: {:#02x}, {:#04x}: {:#02x}",
|
|
||||||
// Goto(1, 36),
|
|
||||||
// 0x30,
|
|
||||||
// self.read(0x30),
|
|
||||||
// 0x31,
|
|
||||||
// self.read(0x31)
|
|
||||||
// );
|
|
||||||
// println!(
|
|
||||||
// "{}cursor - x: {:#02x}, y: {:#02x}",
|
|
||||||
// Goto(1, 37),
|
|
||||||
// self.read(0x300),
|
|
||||||
// self.read(0x301)
|
|
||||||
// );
|
|
||||||
self.stop();
|
self.stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quick_cycle(&mut self) {
|
||||||
|
if !self.get_flag(StatusFlag::IrqDisable) && self.irq {
|
||||||
|
self.interrupt();
|
||||||
|
}
|
||||||
|
let opcode = self.read(self.pc);
|
||||||
|
let instruction = get_instruction(opcode);
|
||||||
|
instruction.call(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_to_end(&mut self) -> [u8; 0x10000] {
|
||||||
|
self.quick_cycle();
|
||||||
|
while self.pending_cycles != 0 {
|
||||||
|
let opcode = self.read(self.pc);
|
||||||
|
let instruction = get_instruction(opcode);
|
||||||
|
match instruction.name {
|
||||||
|
"stp" | "breakpoint" => return self.memory.dump(),
|
||||||
|
_ => self.quick_cycle(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#[derive(Debug)]
|
|
||||||
pub enum GeorgeErrorKind {
|
|
||||||
Memory(MemoryError),
|
|
||||||
Execution(ExecutionError),
|
|
||||||
AddrMode(AddressingModeError),
|
|
||||||
Mapping(MappingError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MemoryError> for GeorgeErrorKind {
|
|
||||||
fn from(value: MemoryError) -> Self {
|
|
||||||
Self::Memory(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<AddressingModeError> for GeorgeErrorKind {
|
|
||||||
fn from(value: AddressingModeError) -> Self {
|
|
||||||
Self::AddrMode(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<ExecutionError> for GeorgeErrorKind {
|
|
||||||
fn from(value: ExecutionError) -> Self {
|
|
||||||
Self::Execution(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ExecutionError {
|
|
||||||
InvalidInstruction,
|
|
||||||
InterruptsDisabled,
|
|
||||||
StackOverflow,
|
|
||||||
MemoryError(MemoryError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AddressingModeError {
|
|
||||||
IncompatibleAddrMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ExecutionError> for AddressingModeError {
|
|
||||||
fn from(_value: ExecutionError) -> Self {
|
|
||||||
Self::IncompatibleAddrMode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MemoryError> for ExecutionError {
|
|
||||||
fn from(error: MemoryError) -> Self {
|
|
||||||
ExecutionError::MemoryError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GeorgeError {
|
|
||||||
pub desc: String,
|
|
||||||
pub kind: GeorgeErrorKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MemoryError {
|
|
||||||
Unmapped,
|
|
||||||
NoDataAtAddress,
|
|
||||||
Unwritable,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MappingError {
|
|
||||||
RegionOccupied,
|
|
||||||
InvalidPage,
|
|
||||||
}
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
# this is august's version of extended ascii for george <3
|
|
||||||
# we're limited to 255 characters
|
|
||||||
# format: ascii byte, unicode hex, # unicode name
|
|
||||||
#
|
|
||||||
# format: three tab-separated columns
|
|
||||||
# column #1 is the ISO/IEC 8859-1 code (in hex as 0xXX)
|
|
||||||
# column #2 is the Unicode (in hex as 0xXXXX)
|
|
||||||
# column #3 the Unicode name (follows a comment sign, '#')
|
|
||||||
|
|
||||||
0x00 0x00 #
|
|
||||||
0x01 0x2591 # ░
|
|
||||||
0x02 0x2592 # ▒
|
|
||||||
0x03 0x2593 # ▓
|
|
||||||
0x04 0x2661 # ♡
|
|
||||||
0x05 0x2665 # ♥
|
|
||||||
0x06 0x2B50 # ⭐
|
|
||||||
0x07 0x272D # ✭
|
|
||||||
0x08 0xF005 #
|
|
||||||
0x09 0x2726 # ✦
|
|
||||||
0x0a 0x2728 # ✨
|
|
||||||
0x0b 0x2640 # ♀
|
|
||||||
0x0c 0x2642 # ♂
|
|
||||||
0x0d 0x26A2 # ⚢
|
|
||||||
0x0E 0x26A3 # ⚣
|
|
||||||
0x0F 0x26A5 # ⚥
|
|
||||||
0x10 0x2669 # ♩
|
|
||||||
0x11 0x266A # ♪
|
|
||||||
0x12 0x266B # ♫
|
|
||||||
0x13 0x266C # ♬
|
|
||||||
0x14 0xFC5D # ﱝ
|
|
||||||
0x15 0xF026 #
|
|
||||||
0x16 0xF027 #
|
|
||||||
0x17 0xF028 #
|
|
||||||
0x18 0xFA7E # 奄
|
|
||||||
0x19 0xFA7F # 奔
|
|
||||||
0x1A 0xFA80 # 婢
|
|
||||||
0x1B 0xFC5C # ﱜ
|
|
||||||
0x1C 0xFC5B # ﱛ
|
|
||||||
0x1D 0xF0AC #
|
|
||||||
0x1E 0xF04B #
|
|
||||||
0x1F 0xF04D #
|
|
||||||
0x20 0x0020 #
|
|
||||||
0x21 0x0021 # !
|
|
||||||
0x22 0x0022 # "
|
|
||||||
0x23 0x0023 # #
|
|
||||||
0x24 0x0024 # $
|
|
||||||
0x25 0x0025 # %
|
|
||||||
0x26 0x0026 # &
|
|
||||||
0x27 0x0027 # '
|
|
||||||
0x28 0x0028 # (
|
|
||||||
0x29 0x0029 # )
|
|
||||||
0x2A 0x002A # *
|
|
||||||
0x2B 0x002B # +
|
|
||||||
0x2C 0x002C # ,
|
|
||||||
0x2D 0x002D # -
|
|
||||||
0x2E 0x002E # .
|
|
||||||
0x2F 0x002F # /
|
|
||||||
0x30 0x0030 # 0
|
|
||||||
0x31 0x0031 # 1
|
|
||||||
0x32 0x0032 # 2
|
|
||||||
0x33 0x0033 # 3
|
|
||||||
0x34 0x0034 # 4
|
|
||||||
0x35 0x0035 # 5
|
|
||||||
0x36 0x0036 # 6
|
|
||||||
0x37 0x0037 # 7
|
|
||||||
0x38 0x0038 # 8
|
|
||||||
0x39 0x0039 # 9
|
|
||||||
0x3A 0x003A # :
|
|
||||||
0x3B 0x003B # ;
|
|
||||||
0x3C 0x003C # <
|
|
||||||
0x3D 0x003D # =
|
|
||||||
0x3E 0x003E # >
|
|
||||||
0x3F 0x003F # ?
|
|
||||||
0x40 0x0040 # @
|
|
||||||
0x41 0x0041 # A
|
|
||||||
0x42 0x0042 # B
|
|
||||||
0x43 0x0043 # C
|
|
||||||
0x44 0x0044 # D
|
|
||||||
0x45 0x0045 # E
|
|
||||||
0x46 0x0046 # F
|
|
||||||
0x47 0x0047 # G
|
|
||||||
0x48 0x0048 # H
|
|
||||||
0x49 0x0049 # I
|
|
||||||
0x4A 0x004A # J
|
|
||||||
0x4B 0x004B # K
|
|
||||||
0x4C 0x004C # L
|
|
||||||
0x4D 0x004D # M
|
|
||||||
0x4E 0x004E # N
|
|
||||||
0x4F 0x004F # O
|
|
||||||
0x50 0x0050 # P
|
|
||||||
0x51 0x0051 # Q
|
|
||||||
0x52 0x0052 # R
|
|
||||||
0x53 0x0053 # S
|
|
||||||
0x54 0x0054 # T
|
|
||||||
0x55 0x0055 # U
|
|
||||||
0x56 0x0056 # V
|
|
||||||
0x57 0x0057 # W
|
|
||||||
0x58 0x0058 # X
|
|
||||||
0x59 0x0059 # Y
|
|
||||||
0x5A 0x005A # Z
|
|
||||||
0x5B 0x005B # [
|
|
||||||
0x5C 0x005C # \
|
|
||||||
0x5D 0x005D # ]
|
|
||||||
0x5E 0x005E # ^
|
|
||||||
0x5F 0x005F # _
|
|
||||||
0x60 0x0060 # `
|
|
||||||
0x61 0x0061 # a
|
|
||||||
0x62 0x0062 # b
|
|
||||||
0x63 0x0063 # c
|
|
||||||
0x64 0x0064 # d
|
|
||||||
0x65 0x0065 # e
|
|
||||||
0x66 0x0066 # f
|
|
||||||
0x67 0x0067 # g
|
|
||||||
0x68 0x0068 # h
|
|
||||||
0x69 0x0069 # i
|
|
||||||
0x6A 0x006A # j
|
|
||||||
0x6B 0x006B # k
|
|
||||||
0x6C 0x006C # l
|
|
||||||
0x6D 0x006D # m
|
|
||||||
0x6E 0x006E # n
|
|
||||||
0x6F 0x006F # o
|
|
||||||
0x70 0x0070 # p
|
|
||||||
0x71 0x0071 # q
|
|
||||||
0x72 0x0072 # r
|
|
||||||
0x73 0x0073 # s
|
|
||||||
0x74 0x0074 # t
|
|
||||||
0x75 0x0075 # u
|
|
||||||
0x76 0x0076 # v
|
|
||||||
0x77 0x0077 # w
|
|
||||||
0x78 0x0078 # x
|
|
||||||
0x79 0x0079 # y
|
|
||||||
0x7A 0x007A # z
|
|
||||||
0x7B 0x007B # {
|
|
||||||
0x7C 0x007C # |
|
|
||||||
0x7D 0x007D # }
|
|
||||||
0x7E 0x007E # ~
|
|
||||||
0x7F 0x2500 # ─
|
|
||||||
0x80 0x2502 # │
|
|
||||||
0x81 0x250C # ┌
|
|
||||||
0x82 0x2514 # └
|
|
||||||
0x83 0x251C # ├
|
|
||||||
0x84 0x2524 # ┤
|
|
||||||
0x85 0x252C # ┬
|
|
||||||
0x86 0x2534 # ┴
|
|
||||||
0x87 0x253C # ┼
|
|
||||||
0x88 0x256D # ╭
|
|
||||||
0x89 0x256E # ╮
|
|
||||||
0x8A 0x256F # ╯
|
|
||||||
0x8B 0x2570 # ╰
|
|
||||||
0x8C 0x2571 # ╱
|
|
||||||
0x8D 0x2572 # ╲
|
|
||||||
0x8E 0x2573 # ╳
|
|
||||||
0x8F 0x2550 # ═
|
|
||||||
0x90 0x2551 # ║
|
|
||||||
0x91 0x2554 # ╔
|
|
||||||
0x92 0x2557 # ╗
|
|
||||||
0x93 0x255a # ╚
|
|
||||||
0x94 0x255D # ╝
|
|
||||||
0x95 0x2560 # ╠
|
|
||||||
0x96 0x2563 # ╣
|
|
||||||
0x97 0x2566 # ╦
|
|
||||||
0x98 0x2569 # ╩
|
|
||||||
0x99 0x256C # ╬
|
|
||||||
0x9A 0xF04E #
|
|
||||||
0x9B 0xF050 #
|
|
||||||
0x9C 0xF051 #
|
|
||||||
0x9D 0xF052 #
|
|
||||||
0x9E 0xF048 #
|
|
||||||
0x9F 0xE0B0 #
|
|
||||||
0xA0 0xE0B2 #
|
|
||||||
0xA1 0xE0B4 #
|
|
||||||
0xA2 0xE0B6 #
|
|
||||||
0xA3 0xE0B8 #
|
|
||||||
0xA4 0xE0BA #
|
|
||||||
0xA5 0xE0BC #
|
|
||||||
0xA6 0xE0BE #
|
|
||||||
0xA7 0x2581 # ▁
|
|
||||||
0xA8 0x2582 # ▂
|
|
||||||
0xA9 0x2583 # ▃
|
|
||||||
0xAA 0x2584 # ▄
|
|
||||||
0xAB 0x2585 # ▅
|
|
||||||
0xAC 0x2586 # ▆
|
|
||||||
0xAD 0x2587 # ▇
|
|
||||||
0xAE 0x2588 # █
|
|
||||||
0xAF 0x2589 # ▉
|
|
||||||
0xB0 0x258A # ▊
|
|
||||||
0xB1 0x258B # ▋
|
|
||||||
0xB2 0x258C # ▌
|
|
||||||
0xB3 0x258D # ▍
|
|
||||||
0xB4 0x258E # ▎
|
|
||||||
0xB5 0x258F # ▏
|
|
||||||
0xB6 0x0295 # ʕ
|
|
||||||
0xB7 0x00B7 # ·
|
|
||||||
0xB8 0x1D25 # ᴥ
|
|
||||||
0xB9 0x0294 # ʔ
|
|
||||||
0xBA 0x2596 # ▖
|
|
||||||
0xBB 0x2597 # ▗
|
|
||||||
0xBC 0x2598 # ▘
|
|
||||||
0xBD 0x2599 # ▙
|
|
||||||
0xBE 0x259A # ▚
|
|
||||||
0xBF 0x259B # ▛
|
|
||||||
0xC0 0x259C # ▜
|
|
||||||
0xC1 0x259D # ▝
|
|
||||||
0xC2 0x259E # ▞
|
|
||||||
0xC3 0x259F # ▟
|
|
||||||
0xC4 0x2190 # ←
|
|
||||||
0xC5 0x2191 # ↑
|
|
||||||
0xC6 0x2192 # →
|
|
||||||
0xC7 0x2193 # ↓
|
|
||||||
0xC8 0x2B60 # ⭠
|
|
||||||
0xC9 0x2B61 # ⭡
|
|
||||||
0xCA 0x2B62 # ⭢
|
|
||||||
0xCB 0x2B63 # ⭣
|
|
||||||
0xCC 0x2B80 # ⮀
|
|
||||||
0xCD 0x2B81 # ⮁
|
|
||||||
0xCE 0x2B82 # ⮂
|
|
||||||
0xCF 0x2B83 # ⮃
|
|
||||||
0xD0 0xF049 #
|
|
||||||
0xD1 0xF04A #
|
|
||||||
0xD2 0x23F3 # ⏳
|
|
||||||
0xD3 0xF07B #
|
|
||||||
0xD4 0xF07C #
|
|
||||||
0xD5 0xF114 #
|
|
||||||
0xD6 0xF115 #
|
|
||||||
0xD7 0xF250 #
|
|
||||||
0xD8 0xF251 #
|
|
||||||
0xD9 0xF253 #
|
|
||||||
0xDA 0xF254 #
|
|
||||||
0xDB 0xF461 #
|
|
||||||
0xDC 0xF016 #
|
|
||||||
0xDD 0xF401 #
|
|
||||||
0xDE 0x1F52E # 🔮
|
|
||||||
0xDF 0xF2DB #
|
|
||||||
0xE0 0xF008 #
|
|
||||||
0xE1 0x25C7 # ◇
|
|
||||||
0xE2 0x25C8 # ◈
|
|
||||||
0xE3 0x1F311 # 🌑
|
|
||||||
0xE4 0x1F312 # 🌒
|
|
||||||
0xE5 0x1F313 # 🌓
|
|
||||||
0xE6 0x1F314 # 🌔
|
|
||||||
0xE7 0x1F315 # 🌕
|
|
||||||
0xE8 0x1F316 # 🌖
|
|
||||||
0xE9 0x1F317 # 🌗
|
|
||||||
0xEA 0x1F318 # 🌘
|
|
||||||
0xEB 0xF04C #
|
|
||||||
0xEC 0x2714 # ✔
|
|
||||||
0xED 0x2718 # ✘
|
|
||||||
0xEE 0x25C6 # ◆
|
|
||||||
0xEF 0xF15D #
|
|
||||||
0xF0 0xF15E #
|
|
||||||
0xF1 0xF071 #
|
|
||||||
0xF2 0xF449 #
|
|
||||||
0xF3 0xF529 #
|
|
||||||
0xF4 0xF658 #
|
|
||||||
0xF5 0xF659 #
|
|
||||||
0xF6 0x1f381 # 🎁
|
|
||||||
0xF7 0xf05a #
|
|
||||||
0xF8 0xf06a #
|
|
||||||
0xF9 0xf834 #
|
|
||||||
0xFA 0xf835 #
|
|
||||||
0xFB 0x2690 # ⚐
|
|
||||||
0xFC 0x2691 # ⚑
|
|
||||||
0xFD 0xf8d7 #
|
|
||||||
0xFE 0xf0e7 #
|
|
||||||
0xFF 0xf7d9 #
|
|
||||||
+201
-134
@@ -1,10 +1,9 @@
|
|||||||
#![allow(clippy::upper_case_acronyms)]
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
|
|
||||||
use core::panic;
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::process::exit;
|
use termion::{clear, color, cursor::Goto};
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
use termion::cursor::Goto;
|
use web_sys::console;
|
||||||
use termion::{clear, color};
|
|
||||||
|
|
||||||
use crate::cpu::{Cpu, StatusFlag};
|
use crate::cpu::{Cpu, StatusFlag};
|
||||||
use crate::memory::{MemoryReader, MemoryWriter};
|
use crate::memory::{MemoryReader, MemoryWriter};
|
||||||
@@ -23,47 +22,13 @@ pub struct Instruction<'a> {
|
|||||||
|
|
||||||
impl Instruction<'_> {
|
impl Instruction<'_> {
|
||||||
pub fn call(&self, cpu: &mut Cpu) {
|
pub fn call(&self, cpu: &mut Cpu) {
|
||||||
// TODO: add flag to print these
|
if cpu.debug {
|
||||||
// print!("{}{}a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", Goto(0, 31),clear::UntilNewline, a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
|
self.debug(cpu);
|
||||||
// print!(
|
}
|
||||||
// "{}instruction: {:?}, pc: {:#04x}",
|
|
||||||
// Goto(0, 31),
|
|
||||||
// self.name,
|
|
||||||
// cpu.pc
|
|
||||||
// );
|
|
||||||
// print!(
|
|
||||||
// "{}{}instruction: {:?}, mode: {:?}",
|
|
||||||
// Goto(0, 32),
|
|
||||||
// clear::UntilNewline,
|
|
||||||
// self.name,
|
|
||||||
// self.addr_mode
|
|
||||||
// );
|
|
||||||
// print!(
|
|
||||||
// "{}{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {}{}{:02x}{}{} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
|
|
||||||
// Goto(0, 33),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(8)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(7)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(6)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(5)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(4)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(3)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(2)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_sub(1)),
|
|
||||||
// color::Bg(color::Rgb(0xFF, 0xCC, 0x00)),
|
|
||||||
// color::Fg(color::Rgb(0x11, 0x05, 0x00)),
|
|
||||||
// cpu.read(cpu.pc),
|
|
||||||
// color::Fg(color::Rgb(0xFF, 0xCC, 0x00)),
|
|
||||||
// color::Bg(color::Rgb(0x11, 0x05, 0x00)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(1)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(2)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(3)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(4)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(5)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(6)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(7)),
|
|
||||||
// cpu.read(cpu.pc.wrapping_add(8)),
|
|
||||||
// );
|
|
||||||
cpu.pc = cpu.pc.wrapping_add(1); // read instruction byte
|
cpu.pc = cpu.pc.wrapping_add(1); // read instruction byte
|
||||||
|
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
match self.instr_fn {
|
match self.instr_fn {
|
||||||
// existence of instr_fn means this is a valid instruction
|
// existence of instr_fn means this is a valid instruction
|
||||||
Some(instr_fn) => {
|
Some(instr_fn) => {
|
||||||
@@ -81,16 +46,119 @@ impl Instruction<'_> {
|
|||||||
} // None for address_fn implies it's implied (lol)/stack
|
} // None for address_fn implies it's implied (lol)/stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None =>
|
||||||
panic!(
|
{
|
||||||
"An invalid instruction was called at {:04x}, with opcode {:02x}",
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
if cpu.debug {
|
||||||
|
println!(
|
||||||
|
"{}An invalid instruction was called at {:04x}, with opcode {:02x}",
|
||||||
|
Goto(0, 35),
|
||||||
cpu.pc,
|
cpu.pc,
|
||||||
cpu.read(cpu.pc)
|
cpu.read(cpu.pc)
|
||||||
|
);
|
||||||
|
cpu.breakpoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug(&self, cpu: &Cpu) {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
|
// cpu state
|
||||||
|
print!("{}{}a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", Goto(0, 31),clear::UntilNewline, a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
|
||||||
|
print!(
|
||||||
|
"{}instruction: {:?}, pc: {:#04x}",
|
||||||
|
Goto(0, 31),
|
||||||
|
self.name,
|
||||||
|
cpu.pc
|
||||||
|
);
|
||||||
|
|
||||||
|
// current instruction and addressing mode
|
||||||
|
print!(
|
||||||
|
"{}{}instruction: {:?}, mode: {:?}",
|
||||||
|
Goto(0, 32),
|
||||||
|
clear::UntilNewline,
|
||||||
|
self.name,
|
||||||
|
self.addr_mode
|
||||||
|
);
|
||||||
|
|
||||||
|
// local memory
|
||||||
|
print!(
|
||||||
|
"{}{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {}{}{:02x}{}{} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
|
||||||
|
Goto(0, 33),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(8)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(7)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(6)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(5)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(4)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(3)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(2)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(1)),
|
||||||
|
color::Bg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||||
|
color::Fg(color::Rgb(0x11, 0x05, 0x00)),
|
||||||
|
cpu.read(cpu.pc),
|
||||||
|
color::Fg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||||
|
color::Bg(color::Rgb(0x11, 0x05, 0x00)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(1)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(2)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(3)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(4)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(5)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(6)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(7)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(8)),
|
||||||
|
);
|
||||||
|
// scratchpad
|
||||||
|
print!(
|
||||||
|
"{} {:02x} {:02x} {:02x}",
|
||||||
|
Goto(0, 34),
|
||||||
|
cpu.read(0x200),
|
||||||
|
cpu.read(0x201),
|
||||||
|
cpu.read(0x202)
|
||||||
)
|
)
|
||||||
} // idk if we should panic here, if we don't it's undefined behavior, which
|
}
|
||||||
// might actually be what we want in the cases where it's an undocumented
|
#[cfg(target_arch = "wasm32")]
|
||||||
// 6502 instruction, but otherwise we should panic prolly, for now i'm just
|
{
|
||||||
// gonna panic
|
let cpu_state = format!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
|
||||||
|
console::log_1(&cpu_state.into());
|
||||||
|
|
||||||
|
let curr_instr = format!("instruction: {:?}, mode: {:?}", self.name, self.addr_mode);
|
||||||
|
console::log_1(&curr_instr.into());
|
||||||
|
|
||||||
|
let local_mem = format!(
|
||||||
|
"{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} %c{:02x}%c {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(8)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(7)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(6)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(5)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(4)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(3)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(2)),
|
||||||
|
cpu.read(cpu.pc.wrapping_sub(1)),
|
||||||
|
cpu.read(cpu.pc),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(1)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(2)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(3)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(4)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(5)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(6)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(7)),
|
||||||
|
cpu.read(cpu.pc.wrapping_add(8)),
|
||||||
|
);
|
||||||
|
console::log_3(
|
||||||
|
&local_mem.into(),
|
||||||
|
&"background: black; color: white".into(),
|
||||||
|
&"background: unset; color: unset".into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let scratchpad = format!(
|
||||||
|
"scratchpad: {:02x} {:02x} {:02x}",
|
||||||
|
cpu.read(0x200),
|
||||||
|
cpu.read(0x201),
|
||||||
|
cpu.read(0x202)
|
||||||
|
);
|
||||||
|
console::log_1(&scratchpad.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +277,6 @@ fn zero_page_indirect_indexed_with_y(
|
|||||||
let address = cpu.read_word(zp as u16);
|
let address = cpu.read_word(zp as u16);
|
||||||
let address: u16 = address.wrapping_add(cpu.y as u16);
|
let address: u16 = address.wrapping_add(cpu.y as u16);
|
||||||
cpu.pc = cpu.pc.wrapping_add(1);
|
cpu.pc = cpu.pc.wrapping_add(1);
|
||||||
println!("{}indirect addr: {:#04x}", Goto(1, 39), address);
|
|
||||||
address
|
address
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +322,7 @@ fn branch(cpu: &mut Cpu, condition: bool, address: u16) {
|
|||||||
cpu.pc = cpu.pc.wrapping_add(1);
|
cpu.pc = cpu.pc.wrapping_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn brkpt(cpu: &mut Cpu, address: Option<u16>) {
|
fn breakpoint(cpu: &mut Cpu, _address: Option<u16>) {
|
||||||
cpu.breakpoint()
|
cpu.breakpoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +331,7 @@ fn adc(cpu: &mut Cpu, address: Option<u16>) {
|
|||||||
let byte = cpu.read(address);
|
let byte = cpu.read(address);
|
||||||
let carry = cpu.get_flag(StatusFlag::Carry);
|
let carry = cpu.get_flag(StatusFlag::Carry);
|
||||||
let result = cpu.a as u16 + byte as u16 + carry as u16;
|
let result = cpu.a as u16 + byte as u16 + carry as u16;
|
||||||
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::max_value()));
|
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::MAX));
|
||||||
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
|
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
|
||||||
cpu.set_flag(
|
cpu.set_flag(
|
||||||
StatusFlag::Overflow,
|
StatusFlag::Overflow,
|
||||||
@@ -786,7 +853,7 @@ fn sbc(cpu: &mut Cpu, address: Option<u16>) {
|
|||||||
let byte = cpu.read(address);
|
let byte = cpu.read(address);
|
||||||
let carry = cpu.get_flag(StatusFlag::Carry);
|
let carry = cpu.get_flag(StatusFlag::Carry);
|
||||||
let result = cpu.a as u16 + byte as u16 + !carry as u16;
|
let result = cpu.a as u16 + byte as u16 + !carry as u16;
|
||||||
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::max_value()));
|
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::MAX));
|
||||||
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
|
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
|
||||||
cpu.set_flag(
|
cpu.set_flag(
|
||||||
StatusFlag::Overflow,
|
StatusFlag::Overflow,
|
||||||
@@ -948,7 +1015,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 7,
|
cycles: 7,
|
||||||
name: "brk",
|
name: "brk",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ora),
|
instr_fn: Some(ora),
|
||||||
@@ -958,18 +1025,18 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
addr_mode: "zero_page_indexed_indirect",
|
addr_mode: "zero_page_indexed_indirect",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(brkpt),
|
instr_fn: Some(breakpoint),
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "brkpt",
|
name: "breakpoint",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "end",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(tsb),
|
instr_fn: Some(tsb),
|
||||||
@@ -1004,7 +1071,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 3,
|
cycles: 3,
|
||||||
name: "php",
|
name: "php",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ora),
|
instr_fn: Some(ora),
|
||||||
@@ -1025,7 +1092,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(tsb),
|
instr_fn: Some(tsb),
|
||||||
@@ -1081,7 +1148,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(trb),
|
instr_fn: Some(trb),
|
||||||
@@ -1116,7 +1183,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "clc",
|
name: "clc",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ora),
|
instr_fn: Some(ora),
|
||||||
@@ -1137,7 +1204,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(trb),
|
instr_fn: Some(trb),
|
||||||
@@ -1186,14 +1253,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(bit),
|
instr_fn: Some(bit),
|
||||||
@@ -1228,7 +1295,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 4,
|
cycles: 4,
|
||||||
name: "plp",
|
name: "plp",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(and),
|
instr_fn: Some(and),
|
||||||
@@ -1249,7 +1316,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(bit),
|
instr_fn: Some(bit),
|
||||||
@@ -1305,7 +1372,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(bit),
|
instr_fn: Some(bit),
|
||||||
@@ -1340,7 +1407,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "sec",
|
name: "sec",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(and),
|
instr_fn: Some(and),
|
||||||
@@ -1361,7 +1428,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(bit),
|
instr_fn: Some(bit),
|
||||||
@@ -1396,7 +1463,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 6,
|
cycles: 6,
|
||||||
name: "rti",
|
name: "rti",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(eor),
|
instr_fn: Some(eor),
|
||||||
@@ -1410,21 +1477,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(eor),
|
instr_fn: Some(eor),
|
||||||
@@ -1452,7 +1519,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 3,
|
cycles: 3,
|
||||||
name: "pha",
|
name: "pha",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(eor),
|
instr_fn: Some(eor),
|
||||||
@@ -1473,7 +1540,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(jmp),
|
instr_fn: Some(jmp),
|
||||||
@@ -1529,14 +1596,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(eor),
|
instr_fn: Some(eor),
|
||||||
@@ -1564,7 +1631,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "cli",
|
name: "cli",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(eor),
|
instr_fn: Some(eor),
|
||||||
@@ -1578,21 +1645,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 3,
|
cycles: 3,
|
||||||
name: "phy",
|
name: "phy",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(eor),
|
instr_fn: Some(eor),
|
||||||
@@ -1620,7 +1687,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 6,
|
cycles: 6,
|
||||||
name: "rts",
|
name: "rts",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(adc),
|
instr_fn: Some(adc),
|
||||||
@@ -1634,14 +1701,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(stz),
|
instr_fn: Some(stz),
|
||||||
@@ -1676,7 +1743,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 4,
|
cycles: 4,
|
||||||
name: "pla",
|
name: "pla",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(adc),
|
instr_fn: Some(adc),
|
||||||
@@ -1697,7 +1764,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(jmp),
|
instr_fn: Some(jmp),
|
||||||
@@ -1753,7 +1820,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(stz),
|
instr_fn: Some(stz),
|
||||||
@@ -1788,7 +1855,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "sei",
|
name: "sei",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(adc),
|
instr_fn: Some(adc),
|
||||||
@@ -1802,14 +1869,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 4,
|
cycles: 4,
|
||||||
name: "ply",
|
name: "ply",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(jmp),
|
instr_fn: Some(jmp),
|
||||||
@@ -1858,14 +1925,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sty),
|
instr_fn: Some(sty),
|
||||||
@@ -1900,7 +1967,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "dey",
|
name: "dey",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(bit),
|
instr_fn: Some(bit),
|
||||||
@@ -1914,14 +1981,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "txa",
|
name: "txa",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sty),
|
instr_fn: Some(sty),
|
||||||
@@ -1977,7 +2044,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sty),
|
instr_fn: Some(sty),
|
||||||
@@ -2012,7 +2079,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "tya",
|
name: "tya",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sta),
|
instr_fn: Some(sta),
|
||||||
@@ -2026,14 +2093,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "txs",
|
name: "txs",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(stz),
|
instr_fn: Some(stz),
|
||||||
@@ -2089,7 +2156,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ldy),
|
instr_fn: Some(ldy),
|
||||||
@@ -2124,7 +2191,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "tay",
|
name: "tay",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(lda),
|
instr_fn: Some(lda),
|
||||||
@@ -2138,14 +2205,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "tax",
|
name: "tax",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ldy),
|
instr_fn: Some(ldy),
|
||||||
@@ -2201,7 +2268,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ldy),
|
instr_fn: Some(ldy),
|
||||||
@@ -2236,7 +2303,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "clv",
|
name: "clv",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(lda),
|
instr_fn: Some(lda),
|
||||||
@@ -2250,14 +2317,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "tsx",
|
name: "tsx",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(ldy),
|
instr_fn: Some(ldy),
|
||||||
@@ -2306,14 +2373,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cpy),
|
instr_fn: Some(cpy),
|
||||||
@@ -2348,7 +2415,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "iny",
|
name: "iny",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cmp),
|
instr_fn: Some(cmp),
|
||||||
@@ -2362,14 +2429,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "dex",
|
name: "dex",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(wai),
|
instr_fn: Some(wai),
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 3,
|
cycles: 3,
|
||||||
name: "wai",
|
name: "wai",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cpy),
|
instr_fn: Some(cpy),
|
||||||
@@ -2425,14 +2492,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cmp),
|
instr_fn: Some(cmp),
|
||||||
@@ -2460,7 +2527,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "cld",
|
name: "cld",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cmp),
|
instr_fn: Some(cmp),
|
||||||
@@ -2474,21 +2541,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 3,
|
cycles: 3,
|
||||||
name: "phx",
|
name: "phx",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(stp),
|
instr_fn: Some(stp),
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 3,
|
cycles: 3,
|
||||||
name: "stp",
|
name: "stp",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cmp),
|
instr_fn: Some(cmp),
|
||||||
@@ -2530,14 +2597,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cpx),
|
instr_fn: Some(cpx),
|
||||||
@@ -2572,7 +2639,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "inx",
|
name: "inx",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sbc),
|
instr_fn: Some(sbc),
|
||||||
@@ -2586,14 +2653,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "nop",
|
name: "nop",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(cpx),
|
instr_fn: Some(cpx),
|
||||||
@@ -2649,14 +2716,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sbc),
|
instr_fn: Some(sbc),
|
||||||
@@ -2684,7 +2751,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
name: "sed",
|
name: "sed",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sbc),
|
instr_fn: Some(sbc),
|
||||||
@@ -2698,21 +2765,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 4,
|
cycles: 4,
|
||||||
name: "plx",
|
name: "plx",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: None,
|
instr_fn: None,
|
||||||
address_fn: None,
|
address_fn: None,
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
name: "none",
|
name: "none",
|
||||||
addr_mode: "none",
|
addr_mode: "implied",
|
||||||
},
|
},
|
||||||
Instruction {
|
Instruction {
|
||||||
instr_fn: Some(sbc),
|
instr_fn: Some(sbc),
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
use minifb::InputCallback;
|
use minifb::InputCallback;
|
||||||
use minifb::Key as MKey;
|
use minifb::Key as MKey;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use termion::event::Key;
|
use termion::event::Key;
|
||||||
|
|
||||||
use crate::memory::{MemHandle, MemoryWriter};
|
use crate::memory::{MemHandle, MemoryWriter};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Keyboard {
|
pub struct Keyboard {
|
||||||
memory: MemHandle,
|
memory: MemHandle,
|
||||||
}
|
}
|
||||||
@@ -13,6 +16,7 @@ impl Keyboard {
|
|||||||
Self { memory }
|
Self { memory }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn clear_keys(&self) {
|
pub fn clear_keys(&self) {
|
||||||
self.memory.write(0x4400, 0x00);
|
self.memory.write(0x4400, 0x00);
|
||||||
self.memory.write(0x4401, 0x00);
|
self.memory.write(0x4401, 0x00);
|
||||||
@@ -22,6 +26,7 @@ impl Keyboard {
|
|||||||
self.memory.write(0x4405, 0x00);
|
self.memory.write(0x4405, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn read_keys(&self, key: Key) {
|
pub fn read_keys(&self, key: Key) {
|
||||||
let mut row0 = 0;
|
let mut row0 = 0;
|
||||||
let mut row1 = 0;
|
let mut row1 = 0;
|
||||||
|
|||||||
+204
@@ -0,0 +1,204 @@
|
|||||||
|
pub mod cpu;
|
||||||
|
mod instructions;
|
||||||
|
mod keyboard;
|
||||||
|
pub mod memory;
|
||||||
|
mod platform;
|
||||||
|
pub mod video;
|
||||||
|
|
||||||
|
use crate::cpu::Cpu;
|
||||||
|
use crate::keyboard::Keyboard;
|
||||||
|
use crate::memory::Mem;
|
||||||
|
use crate::video::Renderer;
|
||||||
|
|
||||||
|
use cpu::CpuController;
|
||||||
|
use memory::MemHandle;
|
||||||
|
use minifb::Window;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use platform::native as imp;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
use platform::wasm as imp;
|
||||||
|
|
||||||
|
pub struct GeorgeEmu(imp::GeorgeEmu);
|
||||||
|
|
||||||
|
impl GeorgeEmu {
|
||||||
|
pub fn builder() -> GeorgeEmuBuilder<NoRom, NoWindow> {
|
||||||
|
GeorgeEmuBuilder::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.0.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.0.cycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.0.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SomeRom();
|
||||||
|
pub struct NoRom();
|
||||||
|
pub struct SomeWindow(Window);
|
||||||
|
pub struct NoWindow();
|
||||||
|
|
||||||
|
pub struct GeorgeEmuBuilder<Rom, Window> {
|
||||||
|
rom: Rom,
|
||||||
|
cpu: Option<Cpu>,
|
||||||
|
keyboard: Option<Keyboard>,
|
||||||
|
renderer: Option<Renderer>,
|
||||||
|
cpu_controller: Option<CpuController>,
|
||||||
|
memory_handle: Option<MemHandle>,
|
||||||
|
window: Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<NoRom, NoWindow> {
|
||||||
|
fn new() -> Self {
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
rom: NoRom(),
|
||||||
|
cpu: None,
|
||||||
|
keyboard: None,
|
||||||
|
renderer: None,
|
||||||
|
cpu_controller: None,
|
||||||
|
memory_handle: None,
|
||||||
|
window: NoWindow(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn rom(self, rom: [u8; 0x8000]) -> GeorgeEmuBuilder<SomeRom, NoWindow> {
|
||||||
|
let mut memory = Mem::new();
|
||||||
|
memory.load_bytes(&rom);
|
||||||
|
let memory_handle = MemHandle::new(memory);
|
||||||
|
|
||||||
|
let (cpu, cpu_controller) = Cpu::new_with_control(memory_handle.clone());
|
||||||
|
|
||||||
|
let Self {
|
||||||
|
renderer,
|
||||||
|
keyboard,
|
||||||
|
window,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
cpu: Some(cpu),
|
||||||
|
rom: SomeRom(),
|
||||||
|
keyboard,
|
||||||
|
renderer,
|
||||||
|
cpu_controller: Some(cpu_controller),
|
||||||
|
memory_handle: Some(memory_handle),
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<SomeRom, NoWindow> {
|
||||||
|
/// Adds a minifb window to the emulator
|
||||||
|
pub fn window(self, mut window: Window) -> GeorgeEmuBuilder<SomeRom, SomeWindow> {
|
||||||
|
let Self {
|
||||||
|
rom,
|
||||||
|
cpu,
|
||||||
|
keyboard,
|
||||||
|
ref cpu_controller,
|
||||||
|
ref memory_handle,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
let renderer = Renderer::new(
|
||||||
|
self.cpu_controller.clone().unwrap(),
|
||||||
|
self.memory_handle.clone().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.set_input_callback(Box::new(Keyboard::new(
|
||||||
|
self.memory_handle.as_ref().unwrap().clone(),
|
||||||
|
)));
|
||||||
|
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
cpu,
|
||||||
|
rom,
|
||||||
|
keyboard,
|
||||||
|
renderer: Some(renderer),
|
||||||
|
cpu_controller: cpu_controller.clone(),
|
||||||
|
memory_handle: memory_handle.clone(),
|
||||||
|
window: SomeWindow(window),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables debug printing and breakpoint triggering
|
||||||
|
pub fn debug(mut self) -> Self {
|
||||||
|
self.cpu.as_mut().unwrap().debug = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn build(self) -> GeorgeEmu {
|
||||||
|
let keyboard = Keyboard::new(self.memory_handle.clone().unwrap());
|
||||||
|
GeorgeEmu(imp::GeorgeEmu::new(
|
||||||
|
self.cpu.unwrap(),
|
||||||
|
self.renderer.unwrap(),
|
||||||
|
Some(keyboard),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<NoRom, SomeWindow> {
|
||||||
|
pub fn rom(self, rom: [u8; 0x8000]) -> GeorgeEmuBuilder<SomeRom, SomeWindow> {
|
||||||
|
let mut memory = Mem::new();
|
||||||
|
memory.load_bytes(&rom);
|
||||||
|
let memory_handle = MemHandle::new(memory);
|
||||||
|
|
||||||
|
let (cpu, cpu_controller) = Cpu::new_with_control(memory_handle.clone());
|
||||||
|
|
||||||
|
let Self {
|
||||||
|
renderer,
|
||||||
|
keyboard,
|
||||||
|
window,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
cpu: Some(cpu),
|
||||||
|
rom: SomeRom(),
|
||||||
|
keyboard,
|
||||||
|
renderer,
|
||||||
|
cpu_controller: Some(cpu_controller),
|
||||||
|
memory_handle: Some(memory_handle),
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables debug printing and breakpoint triggering
|
||||||
|
pub fn debug(mut self) -> Self {
|
||||||
|
self.cpu.as_mut().unwrap().debug = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<SomeRom, SomeWindow> {
|
||||||
|
/// Enables debug printing and breakpoint triggering
|
||||||
|
pub fn debug(mut self) -> Self {
|
||||||
|
self.cpu.as_mut().unwrap().debug = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn build(self) -> GeorgeEmu {
|
||||||
|
let keyboard = Keyboard::new(self.memory_handle.clone().unwrap());
|
||||||
|
GeorgeEmu(imp::GeorgeEmu::new(
|
||||||
|
self.cpu.unwrap(),
|
||||||
|
self.renderer.unwrap(),
|
||||||
|
None,
|
||||||
|
Some(self.window.0),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub fn build(self) -> GeorgeEmu {
|
||||||
|
GeorgeEmu(imp::GeorgeEmu::new(
|
||||||
|
self.cpu.unwrap(),
|
||||||
|
self.renderer.unwrap(),
|
||||||
|
self.window.0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
-74
@@ -1,74 +0,0 @@
|
|||||||
mod cli;
|
|
||||||
mod cpu;
|
|
||||||
mod error;
|
|
||||||
mod instructions;
|
|
||||||
mod keyboard;
|
|
||||||
mod memory;
|
|
||||||
mod types;
|
|
||||||
mod video;
|
|
||||||
|
|
||||||
use crate::cpu::Cpu;
|
|
||||||
use crate::keyboard::Keyboard;
|
|
||||||
use crate::memory::Mem;
|
|
||||||
use crate::video::Screen;
|
|
||||||
|
|
||||||
use cli::get_input;
|
|
||||||
use crossterm::cursor;
|
|
||||||
use memory::MemHandle;
|
|
||||||
use std::io::stdout;
|
|
||||||
use std::thread::{self, sleep};
|
|
||||||
use std::time::Duration;
|
|
||||||
use termion::cursor::Goto;
|
|
||||||
use termion::event::Key;
|
|
||||||
use termion::input::TermRead;
|
|
||||||
use termion::raw::IntoRawMode;
|
|
||||||
use termion::{async_stdin, clear};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let _stdout = stdout().into_raw_mode();
|
|
||||||
let config = get_input();
|
|
||||||
|
|
||||||
let mut memory = Mem::new();
|
|
||||||
let _ = memory.load_rom(&config.rom);
|
|
||||||
|
|
||||||
let shared_memory = MemHandle::new(memory);
|
|
||||||
let screen_memory = shared_memory.clone();
|
|
||||||
let cpu_memory = shared_memory.clone();
|
|
||||||
let keyboard_memory = shared_memory.clone();
|
|
||||||
|
|
||||||
let keyboard = Keyboard::new(keyboard_memory);
|
|
||||||
|
|
||||||
let (mut cpu, cpu_controller) = Cpu::new_with_control(cpu_memory);
|
|
||||||
cpu.reset();
|
|
||||||
|
|
||||||
thread::spawn(move || loop {
|
|
||||||
cpu.cycle();
|
|
||||||
});
|
|
||||||
|
|
||||||
let screen_remote = cpu_controller.clone();
|
|
||||||
|
|
||||||
let mut screen = Screen::new(&config, screen_remote, screen_memory);
|
|
||||||
|
|
||||||
let mut stdin = async_stdin().keys();
|
|
||||||
print!("{}{}", cursor::Hide, clear::All,);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
screen.draw();
|
|
||||||
if let Some(Ok(key)) = stdin.next() {
|
|
||||||
keyboard.read_keys(key);
|
|
||||||
match key {
|
|
||||||
Key::Char('q') => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Key::Char('`') => cpu_controller.toggle(),
|
|
||||||
Key::Char('\n') => cpu_controller.cycle(),
|
|
||||||
Key::Char('i') => cpu_controller.irq(),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
keyboard.clear_keys();
|
|
||||||
}
|
|
||||||
sleep(Duration::from_millis(16));
|
|
||||||
}
|
|
||||||
print!("{}{}{}", clear::All, cursor::Show, Goto(1, 1));
|
|
||||||
}
|
|
||||||
+36
-26
@@ -1,10 +1,6 @@
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use core::panic;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::exit;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::Read};
|
||||||
@@ -16,17 +12,17 @@ impl MemHandle {
|
|||||||
Self(Arc::new(Mutex::new(memory)))
|
Self(Arc::new(Mutex::new(memory)))
|
||||||
}
|
}
|
||||||
pub fn read(&self, address: u16) -> u8 {
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
let memory = self.0.lock().unwrap();
|
let memory = self.0.try_lock().unwrap();
|
||||||
memory.read(address)
|
memory.read(address)
|
||||||
}
|
}
|
||||||
pub fn write(&self, address: u16, data: u8) {
|
pub fn write(&self, address: u16, data: u8) {
|
||||||
let mut memory = self.0.lock().unwrap();
|
let mut memory = self.0.try_lock().unwrap();
|
||||||
memory.write(address, data);
|
memory.write(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(&self) {
|
pub fn dump(&self) -> [u8; 0x10000] {
|
||||||
let memory = self.0.lock().unwrap();
|
let memory = self.0.lock().unwrap();
|
||||||
let _ = memory.dump(PathBuf::from_str("./cpu_dump.bin").unwrap());
|
memory.dump()
|
||||||
}
|
}
|
||||||
pub fn poke(&self, address: u16) {
|
pub fn poke(&self, address: u16) {
|
||||||
let memory = self.0.lock().unwrap();
|
let memory = self.0.lock().unwrap();
|
||||||
@@ -51,18 +47,26 @@ pub struct Mem([u8; 0x10000]);
|
|||||||
|
|
||||||
impl Default for Mem {
|
impl Default for Mem {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self([0; 0x10000])
|
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/roms/george.rom"));
|
||||||
|
let padding = [0; 0x8000];
|
||||||
|
let mem: [u8; 0x10000] = {
|
||||||
|
let mut rom: [u8; 0x10000] = [0; 0x10000];
|
||||||
|
let (one, two) = rom.split_at_mut(padding.len());
|
||||||
|
one.copy_from_slice(&padding);
|
||||||
|
two.copy_from_slice(bytes);
|
||||||
|
rom
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(mem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mem {
|
impl Mem {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Mem::default()
|
Self([0; 0x10000])
|
||||||
}
|
}
|
||||||
pub fn dump(&self, path: PathBuf) -> io::Result<()> {
|
pub fn dump(&self) -> [u8; 0x10000] {
|
||||||
let mut outfile = File::create(path)?;
|
self.0
|
||||||
outfile.write_all(&self.0)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self, address: u16) -> u8 {
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
@@ -97,16 +101,22 @@ impl Mem {
|
|||||||
pub fn poke(&self, address: u16) {
|
pub fn poke(&self, address: u16) {
|
||||||
println!("{:02x}", self.read(address));
|
println!("{:02x}", self.read(address));
|
||||||
}
|
}
|
||||||
//pub fn read_from_bin(&mut self, f: File) -> Result<()> {
|
pub fn load_bytes(&mut self, bytes: &[u8]) {
|
||||||
// let bytes = f.bytes();
|
for (address, byte) in bytes.iter().enumerate() {
|
||||||
// for (address, byte) in bytes.enumerate() {
|
self.write(address as u16 + 0x8000, *byte)
|
||||||
// match byte {
|
}
|
||||||
// Ok(value) => self.write(address as u16, value),
|
}
|
||||||
// Err(_) => {
|
|
||||||
// bail!("couldn't write byte {:#04x}", address);
|
pub fn read_from_bin(&mut self, f: File) -> Result<()> {
|
||||||
// }
|
let bytes = f.bytes();
|
||||||
// }
|
for (address, byte) in bytes.enumerate() {
|
||||||
// }
|
match byte {
|
||||||
// Ok(())
|
Ok(value) => self.write(address as u16 + 0x8000, value),
|
||||||
//}
|
Err(_) => {
|
||||||
|
bail!("couldn't write byte {:#04x}", address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub mod native;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub mod wasm;
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
use minifb::Window;
|
||||||
|
use std::{
|
||||||
|
io::stdout,
|
||||||
|
process::exit,
|
||||||
|
thread::sleep,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
use termion::{
|
||||||
|
async_stdin, clear,
|
||||||
|
cursor::{self, Goto},
|
||||||
|
event::Key,
|
||||||
|
input::TermRead,
|
||||||
|
raw::IntoRawMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{cpu::Cpu, keyboard::Keyboard, video::Renderer};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GeorgeEmu {
|
||||||
|
cpu: Cpu,
|
||||||
|
renderer: Renderer,
|
||||||
|
input: Option<Keyboard>,
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmu {
|
||||||
|
pub fn new(
|
||||||
|
mut cpu: Cpu,
|
||||||
|
renderer: Renderer,
|
||||||
|
input: Option<Keyboard>,
|
||||||
|
window: Option<Window>,
|
||||||
|
) -> Self {
|
||||||
|
cpu.reset();
|
||||||
|
Self {
|
||||||
|
cpu,
|
||||||
|
input,
|
||||||
|
renderer,
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.renderer.render(self.window.as_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.cpu.cycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
if self.window.is_none() {
|
||||||
|
let _ = stdout().into_raw_mode();
|
||||||
|
print!("{}{}", cursor::Hide, clear::All,);
|
||||||
|
}
|
||||||
|
let clock_interval = Duration::from_nanos(500);
|
||||||
|
let frame_interval = Duration::from_millis(16);
|
||||||
|
let mut next_clock = Instant::now() + clock_interval;
|
||||||
|
let mut next_frame = Instant::now() + frame_interval;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
if now >= next_clock {
|
||||||
|
self.cpu.cycle();
|
||||||
|
next_clock += clock_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if now >= next_frame {
|
||||||
|
if self.window.is_none() {
|
||||||
|
self.handle_input();
|
||||||
|
}
|
||||||
|
self.draw();
|
||||||
|
next_frame += frame_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_run = std::cmp::min(next_clock, next_frame);
|
||||||
|
let sleep_dur = next_run - now;
|
||||||
|
sleep(sleep_dur)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_input(&mut self) {
|
||||||
|
let mut stdin = async_stdin().keys();
|
||||||
|
if let Some(Ok(key)) = stdin.next() {
|
||||||
|
match key {
|
||||||
|
Key::Char('q') => {
|
||||||
|
print!("{}{}{}", clear::All, cursor::Show, Goto(1, 1));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
Key::Char('`') => self.cpu.toggle_stopped(),
|
||||||
|
Key::Char('\n') => self.cpu.cycle(),
|
||||||
|
Key::Char('i') => self.cpu.interrupt(),
|
||||||
|
_ => {
|
||||||
|
self.input.as_mut().unwrap().read_keys(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.input.as_mut().unwrap().clear_keys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
use minifb::Window;
|
||||||
|
|
||||||
|
use crate::{cpu::Cpu, video::Renderer};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GeorgeEmu {
|
||||||
|
cpu: Cpu,
|
||||||
|
renderer: Renderer,
|
||||||
|
window: Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmu {
|
||||||
|
pub fn new(mut cpu: Cpu, renderer: Renderer, window: Window) -> Self {
|
||||||
|
cpu.reset();
|
||||||
|
Self {
|
||||||
|
cpu,
|
||||||
|
renderer,
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.renderer.render(Some(&mut self.window));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.cpu.cycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
use std::{u16, u8};
|
|
||||||
|
|
||||||
pub type Byte = u8;
|
|
||||||
pub type Word = u16;
|
|
||||||
+83
-163
@@ -1,133 +1,52 @@
|
|||||||
use minifb::{Scale, ScaleMode, Window, WindowOptions};
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use serde::{Deserialize, Serialize};
|
use std::io::{self, Write};
|
||||||
|
use std::{env, fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use termion::{
|
use termion::{
|
||||||
color::{self, Bg, Color, Fg},
|
color::{self, Bg, Fg},
|
||||||
cursor::Goto,
|
cursor::Goto,
|
||||||
screen::IntoAlternateScreen,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::Config,
|
|
||||||
cpu::CpuController,
|
cpu::CpuController,
|
||||||
keyboard::Keyboard,
|
|
||||||
memory::{MemHandle, MemoryReader},
|
memory::{MemHandle, MemoryReader},
|
||||||
types::{Byte, Word},
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::{self, Read, Write},
|
|
||||||
path::Path,
|
|
||||||
process::exit,
|
|
||||||
thread::sleep,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
};
|
||||||
|
use minifb::Window;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
const FG_COLOR: u32 = 0xFFCC00;
|
const FG_COLOR: u32 = 0xFFCC00;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
const BG_COLOR: u32 = 0x110500;
|
const BG_COLOR: u32 = 0x110500;
|
||||||
|
|
||||||
|
// Wasm colors are ABGR
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
const FG_COLOR: u32 = 0xFF00CCFF;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
const BG_COLOR: u32 = 0xFF000511;
|
||||||
|
|
||||||
const WIDTH: usize = 512;
|
const WIDTH: usize = 512;
|
||||||
const HEIGHT: usize = 380;
|
const HEIGHT: usize = 380;
|
||||||
|
|
||||||
pub fn get_char_bin<P>(char_rom: Option<P>) -> [u8; 0x8000]
|
// pub fn get_char_bin<P>(char_rom: Option<P>) -> [u8; 0x8000]
|
||||||
where
|
// where
|
||||||
P: AsRef<Path>,
|
// P: AsRef<Path>,
|
||||||
{
|
// {
|
||||||
match char_rom {
|
// match char_rom {
|
||||||
Some(path) => {
|
// Some(path) => {
|
||||||
let mut file = File::open(path).unwrap();
|
// let mut file = File::open(path).unwrap();
|
||||||
let mut bin = vec![0; 0x8000];
|
// let mut bin = vec![0; 0x8000];
|
||||||
file.read_exact(&mut bin).unwrap();
|
// file.read_exact(&mut bin).unwrap();
|
||||||
// println!("reading char rom");
|
// // println!("reading char rom");
|
||||||
bin.try_into().unwrap()
|
// bin.try_into().unwrap()
|
||||||
}
|
// }
|
||||||
None => *include_bytes!("./roms/cozette.rom"),
|
// None => *include_bytes!("./roms/cozette.rom"),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
trait Renderer {
|
const CHAR_ROM: &[u8; 0x8000] = include_bytes!(concat!(env!("OUT_DIR"), "/cozette.rom"));
|
||||||
fn render(&mut self) {}
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
}
|
const ASCII_LOOKUP: [&str; 256] = [
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
|
||||||
pub enum ScreenType {
|
|
||||||
Window,
|
|
||||||
#[default]
|
|
||||||
Terminal,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WindowRenderer {
|
|
||||||
char_rom: [u8; 0x8000],
|
|
||||||
window: Window,
|
|
||||||
memory: MemHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowRenderer {
|
|
||||||
pub fn new<P>(memory: MemHandle, char_rom: Option<P>, window: Window) -> Self
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
let char_rom = get_char_bin(char_rom);
|
|
||||||
Self {
|
|
||||||
memory,
|
|
||||||
window,
|
|
||||||
char_rom,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Renderer for WindowRenderer {
|
|
||||||
fn render(&mut self) {
|
|
||||||
// the rest of this function is arcane wizardry
|
|
||||||
// based on the specifics of george's weird
|
|
||||||
// display and characters... don't fuck around w it
|
|
||||||
let mut i = 0;
|
|
||||||
let mut buffer = [0; 512 * 380];
|
|
||||||
for char_row in 0..29 {
|
|
||||||
for char_col in 0..64 {
|
|
||||||
let ascii = self.read(0x6000 + i);
|
|
||||||
i += 1;
|
|
||||||
for row in 0..13 {
|
|
||||||
let byte = self.char_rom[ascii as usize + (row * 0x100)];
|
|
||||||
for bit_index in (0..8).rev() {
|
|
||||||
let buffer_index =
|
|
||||||
((char_row) * 13 + (row)) * 512 + (char_col * 8 + bit_index);
|
|
||||||
if (byte << bit_index) & 0x80 == 0x80 {
|
|
||||||
buffer[buffer_index] = FG_COLOR;
|
|
||||||
} else {
|
|
||||||
buffer[buffer_index] = BG_COLOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.window
|
|
||||||
.update_with_buffer(&buffer, WIDTH, HEIGHT)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryReader for WindowRenderer {
|
|
||||||
fn read(&self, address: Word) -> Byte {
|
|
||||||
self.memory.read(address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TerminalRenderer {
|
|
||||||
memory: MemHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TerminalRenderer {
|
|
||||||
pub fn new(memory: MemHandle) -> Self {
|
|
||||||
Self { memory }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemoryReader for TerminalRenderer {
|
|
||||||
fn read(&self, address: Word) -> Byte {
|
|
||||||
self.memory.read(address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ASCII_LOOPUP: [&str; 256] = [
|
|
||||||
" ", "░", "▒", "▓", "♡", "♥", "⭐", "✭", "", "✦", "✨", "♀", "♂", "⚢", "⚣", "⚥", "♩", "♪",
|
" ", "░", "▒", "▓", "♡", "♥", "⭐", "✭", "", "✦", "✨", "♀", "♂", "⚢", "⚣", "⚥", "♩", "♪",
|
||||||
"♫", "♬", "ﱝ", "", "", "", "奄", "奔", "婢", "ﱜ", "ﱛ", "", "", "", " ", "!", "\"", "#",
|
"♫", "♬", "ﱝ", "", "", "", "奄", "奔", "婢", "ﱜ", "ﱛ", "", "", "", " ", "!", "\"", "#",
|
||||||
"$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6",
|
"$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6",
|
||||||
@@ -144,15 +63,55 @@ const ASCII_LOOPUP: [&str; 256] = [
|
|||||||
"", "", "", "", "🎁", "", "", "", "", "⚐", "⚑", "", "", "",
|
"", "", "", "", "🎁", "", "", "", "", "⚐", "⚑", "", "", "",
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Renderer for TerminalRenderer {
|
#[derive(Debug)]
|
||||||
fn render(&mut self) {
|
pub struct Renderer {
|
||||||
|
memory: MemHandle,
|
||||||
|
controller: CpuController,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
pub fn new(controller: CpuController, memory: MemHandle) -> Self {
|
||||||
|
Self { memory, controller }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, window: Option<&mut Window>) {
|
||||||
|
match window {
|
||||||
|
Some(window) => {
|
||||||
|
// the rest of this function is arcane wizardry
|
||||||
|
// based on the specifics of george's weird
|
||||||
|
// display and characters... don't fuck around w it
|
||||||
|
let mut i = 0;
|
||||||
|
let mut buffer = [0; WIDTH * HEIGHT];
|
||||||
|
for char_row in 0..29 {
|
||||||
|
for char_col in 0..64 {
|
||||||
|
let ascii = self.read(0x6000 + i);
|
||||||
|
i += 1;
|
||||||
|
for row in 0..13 {
|
||||||
|
let byte = CHAR_ROM[ascii as usize + (row * 0x100)];
|
||||||
|
for bit_index in (0..8).rev() {
|
||||||
|
let buffer_index =
|
||||||
|
((char_row) * 13 + (row)) * 512 + (char_col * 8 + bit_index);
|
||||||
|
if (byte << bit_index) & 0x80 == 0x80 {
|
||||||
|
buffer[buffer_index] = FG_COLOR;
|
||||||
|
} else {
|
||||||
|
buffer[buffer_index] = BG_COLOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
let mut stdout = io::stdout();
|
let mut stdout = io::stdout();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for char_row in 0..29 {
|
for char_row in 0..29 {
|
||||||
for char_col in 0..64 {
|
for char_col in 0..64 {
|
||||||
let ascii = self.read(0x6000 + i);
|
let ascii = self.read(0x6000 + i);
|
||||||
i += 1;
|
i += 1;
|
||||||
let char = ASCII_LOOPUP[ascii as usize];
|
let char = ASCII_LOOKUP[ascii as usize];
|
||||||
let _ = write!(
|
let _ = write!(
|
||||||
// FG_COLOR = 0xFFCC00
|
// FG_COLOR = 0xFFCC00
|
||||||
// BG_COLOR = 0x110500
|
// BG_COLOR = 0x110500
|
||||||
@@ -165,53 +124,14 @@ impl Renderer for TerminalRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Screen {
|
|
||||||
renderer: Box<dyn Renderer>,
|
|
||||||
controller: CpuController,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Screen {
|
|
||||||
pub fn new(config: &Config, controller: CpuController, memory: MemHandle) -> Self {
|
|
||||||
let renderer: Box<dyn Renderer> = match config.screen {
|
|
||||||
ScreenType::Window => {
|
|
||||||
let mut window = Window::new(
|
|
||||||
"ʕ·ᴥ·ʔ-☆",
|
|
||||||
512,
|
|
||||||
380,
|
|
||||||
WindowOptions {
|
|
||||||
resize: true,
|
|
||||||
borderless: true,
|
|
||||||
title: true,
|
|
||||||
transparency: false,
|
|
||||||
scale: Scale::FitScreen,
|
|
||||||
scale_mode: ScaleMode::AspectRatioStretch,
|
|
||||||
topmost: false,
|
|
||||||
none: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
window.set_input_callback(Box::new(Keyboard::new(memory.clone())));
|
|
||||||
Box::new(WindowRenderer::new(memory, config.char_rom.clone(), window))
|
|
||||||
}
|
|
||||||
ScreenType::Terminal => Box::new(TerminalRenderer::new(memory)),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
|
||||||
renderer,
|
|
||||||
controller,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn draw(&mut self) {
|
|
||||||
self.controller.irq();
|
self.controller.irq();
|
||||||
self.renderer.render();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// pub fn run(&mut self) {
|
|
||||||
// loop {
|
impl MemoryReader for Renderer {
|
||||||
// // sleep(Duration::from_millis(16));
|
fn read(&self, address: u16) -> u8 {
|
||||||
// self.draw();
|
self.memory.read(address)
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user