浏览代码

lots of work on ceres-asm (not working yet)

master
Isabelle L. 5 年前
父节点
当前提交
cdd8206756
共有 8 个文件被更改,包括 243 次插入58 次删除
  1. +7
    -6
      Cargo.lock
  2. +16
    -1
      README.md
  3. +1
    -0
      ceres-asm/Cargo.toml
  4. +184
    -21
      ceres-asm/src/lib.rs
  5. +10
    -0
      ceres-sys/src/video.rs
  6. +10
    -0
      justfile
  7. +13
    -25
      src/main.rs
  8. +2
    -5
      test.asm

+ 7
- 6
Cargo.lock 查看文件

@@ -81,6 +81,7 @@ name = "ceres-asm"
version = "0.1.0"
dependencies = [
"logos 0.11.4 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -428,7 +429,7 @@ version = "0.1.0"
dependencies = [
"image 0.23.5 (registry+https://github.com/rust-lang/crates.io-index)",
"minifb 0.16.0 (git+https://github.com/emoon/rust_minifb)",
"thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
@@ -829,15 +830,15 @@ dependencies = [

[[package]]
name = "thiserror"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "thiserror-impl"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1109,8 +1110,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344"
"checksum thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479"
"checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
"checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
"checksum tiff 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f3b8a87c4da944c3f27e5943289171ac71a6150a79ff6bacfff06d159dfff2f"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"


+ 16
- 1
README.md 查看文件

@@ -2,6 +2,7 @@
a shitty fantasy console written in rust using a proprietary MIPS based asm instruction set. a lot of inspiration from PICO-8. ceres is structured of these crates:

- ceres-sys: the core system structure of ceres-16
- ceres-asm: the assembler for ceres-16

### Graphics

@@ -24,4 +25,18 @@ all registers are unsigned 16 bit

### Memory map and info

god oh fuck what am i even doing
god oh fuck what am i even doing

### instructions

##### load - ld:signifier

can be vram/cram/imed

- immediate `ld:immd $dest immediate`

| opcode | signifier | destination | padding | immediate |
| ------- | --------- | ----------- | ------- | ------------------ |
| `00001` | `100` | `0000` | `0000` | `0000000000000000` |


+ 1
- 0
ceres-asm/Cargo.toml 查看文件

@@ -8,3 +8,4 @@ edition = "2018"

[dependencies]
logos = "0.11.4"
thiserror = "1.0.20"

+ 184
- 21
ceres-asm/src/lib.rs 查看文件

@@ -1,14 +1,107 @@
use logos::Logos;
// izzy do not forget to remove these later dummy
#![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_variables)]

// namespacing
use logos::{Lexer, Logos};

/// ceres-asm result type
pub type Result<T> = std::result::Result<T, CeresAsmError>;

/// ceres-asm error type
#[derive(Debug, thiserror::Error)]
pub enum CeresAsmError {
#[error("wrong token found:\nexpected: {expected:?}\n found: {found:?}")]
BadToken { expected: Token, found: Token },
#[error("bad token: {token:?}")]
LazyBadToken { token: Token },
#[error("was looking for token, found nothing ???")]
NoToken,
}

/// assembler struct
pub struct Assembler<'a> {
lexer: Lexer<'a, Token>,
}

impl<'a> Assembler<'a> {
/// create a new assembler
pub fn new(data: &'a str) -> Assembler<'a> {
let lexer = Token::lexer(data);
Assembler { lexer }
}

/// assemble
pub fn assemble(&mut self) -> Result<Vec<u32>> {
let mut machine_code: Vec<u32> = Vec::new();

while let Some(token) = self.lexer.next() {
match token {
// cases that should continue
Token::Comment => continue,
Token::Newline => continue,
// cases that like, actually make sense to process
Token::Load => {
if let Some(new_token) = self.lexer.next() {
let signifier = Signifier::from_token(new_token)?;
machine_code.push(self.load(signifier)?);
} else {
return Err(CeresAsmError::NoToken);
}
}
// cases that should straight up not happen
_ => return Err(CeresAsmError::LazyBadToken { token }),
}
}

Ok(machine_code)
}

// load instruction assembly
fn load(&mut self, signifier: Signifier) -> Result<u32> {
let opcode: u32 = 0b00001;
let signifier: u32 = signifier.as_bits() as u32;
let instruction: u32 = (opcode << 27) | (signifier << 24);
Ok(instruction)
}
}

enum Signifier {
VideoMemory,
CartMemory,
Immediate,
}

impl Signifier {
fn from_token(token: Token) -> Result<Self> {
match token {
Token::VideoMemory => Ok(Self::VideoMemory),
Token::CartMemory => Ok(Self::CartMemory),
Token::Immediate => Ok(Self::Immediate),
_ => Err(CeresAsmError::LazyBadToken { token }),
}
}

// returns the signifier as bits stored in a u8
fn as_bits(self) -> u8 {
match self {
Self::VideoMemory => 0b010,
Self::CartMemory => 0b001,
Self::Immediate => 0b100,
}
}
}

/// token
#[derive(Logos, Debug, PartialEq)]
pub enum Token {
// general stuff
#[regex(";.+")]
Comment,
#[token("@")]
At,
#[regex("/[a-z-_]+:/g")]
Label,
#[token("\n")]
Newline,

// registers
#[token("$t0")]
ZeroRegister,
@@ -25,13 +118,21 @@ pub enum Token {
#[token("$a2")]
ArgumentTwo,
#[token("$v0")]
ReturnOne,
ReturnZero,
#[token("$v1")]
ReturnTwo,
#[regex("\\$t[0-6]")]
TemoraryRegister,
#[regex("\\$[0-9]+")]
RegisterIndex,
ReturnOne,
#[regex("\\$t[0-6]", |lex| lex.slice()[2..].parse::<u16>())]
TemporaryRegister(u16),
#[regex("\\$[0-9]+", |lex| lex.slice()[1..].parse::<u16>())]
RegisterIndex(u16),

// types
#[token("immd")]
Immediate,
#[token("vram")]
VideoMemory,
#[token("cram")]
CartMemory,

// literals
#[regex("0x[a-fA-F0-9]+", |lex| u16::from_str_radix(&lex.slice()[2..], 16).unwrap() )]
@@ -42,18 +143,80 @@ pub enum Token {
DecimalLiteral(u16),

// instructions
#[token("add")]
Add,
#[token("sub")]
Sub,
#[token("mul")]
Mul,
#[token("div")]
Div,
#[token("jmp")]
Jmp,
#[token("ld:")]
Load,

// logos error
#[error]
#[regex(" +", logos::skip)]
Error,
}

impl Token {
// returns the token as a str
fn as_str(&self) -> String {
match self {
// general stuff
Self::Comment => "a comment".to_owned(),
Self::Newline => "\\n".to_owned(),
// registers
Self::ZeroRegister => "$z0".to_owned(),
Self::ProgramCounter => "$pc".to_owned(),
Self::StackPointer => "$sp".to_owned(),
Self::ReturnAddress => "$ra".to_owned(),
Self::ArgumentZero => "$a0".to_owned(),
Self::ArgumentOne => "$z1".to_owned(),
Self::ArgumentTwo => "$a2".to_owned(),
Self::ReturnZero => "$v0".to_owned(),
Self::ReturnOne => "$v1".to_owned(),
Self::TemporaryRegister(idx) => format!("$t{}", idx),
Self::RegisterIndex(idx) => format!("${}", idx),
// types
Self::Immediate => "immd".to_owned(),
Self::VideoMemory => "vram".to_owned(),
Self::CartMemory => "cram".to_owned(),
// literals
Self::HexLiteral(_) => "hex lit".to_owned(),
Self::BinaryLiteral(_) => "bin lit".to_owned(),
Self::DecimalLiteral(_) => "dec lit".to_owned(),
// instructions
Self::Load => "ld:".to_owned(),
// errors
Self::Error => "ERR".to_owned(),
}
}

// returns true if given token is a register
fn is_register(&self) -> bool {
match self {
Self::ZeroRegister
| Self::ProgramCounter
| Self::StackPointer
| Self::ReturnAddress
| Self::ArgumentZero
| Self::ArgumentOne
| Self::ArgumentTwo
| Self::ReturnZero
| Self::ReturnOne
| Self::TemporaryRegister(_)
| Self::RegisterIndex(_) => true,
_ => false,
}
}

// returns true if given token is a literal
fn is_literal(&self) -> bool {
match self {
Self::HexLiteral(_) | Self::BinaryLiteral(_) | Self::DecimalLiteral(_) => true,
_ => false,
}
}

// returns true if it's a valid memory location or immediate
fn is_signifier(&self) -> bool {
match self {
Self::VideoMemory | Self::CartMemory | Self::Immediate => true,
_ => false,
}
}
}

+ 10
- 0
ceres-sys/src/video.rs 查看文件

@@ -8,6 +8,16 @@ impl VideoMemory {
pub fn init() -> VideoMemory {
VideoMemory { data: [0x0000; crate::VIDEO_MEMORY_LEN] }
}

/// an iterator
pub fn iter(&self) -> impl Iterator<Item = &u16> {
self.data.iter()
}

/// mutable iterator
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut u16> {
self.data.iter_mut()
}
}

impl std::ops::Index<u16> for VideoMemory {


+ 10
- 0
justfile 查看文件

@@ -0,0 +1,10 @@
alias r := run
alias b := build

build:
clear
cargo build

run:
clear
cargo run

+ 13
- 25
src/main.rs 查看文件

@@ -6,12 +6,18 @@ use structopt::StructOpt;
struct Opt {
/// times the screen should be scaled by
#[structopt(short = "s", long = "scale", default_value = "4")]
scale_factor: usize,
_scale_factor: usize,
}

fn wrapper() -> Result<()> {
let opt = Opt::from_args();
// load options
let _opt = Opt::from_args();

// initialize the system
let _sys = ceres_sys::System::init();

/*
// create a new graphics context
let mut ctx = offbrand::Context::new(
ceres_sys::SCREEN_WIDTH,
ceres_sys::SCREEN_HEIGHT,
@@ -19,25 +25,12 @@ fn wrapper() -> Result<()> {
Some(opt.scale_factor),
)?;

let mut sys = ceres_sys::System::init();

let mut colors: Vec<u16> = Vec::new();

for r in 0x0..0xf {
for g in 0x0..0xf {
for b in 0x0..0xf {
colors.push((r << 8) | (g << 4) | b);
}
}
}

colors.iter().enumerate().for_each(|(addr, color)| {
sys.video_memory[addr as u16] = *color;
});

// loop while the context window is open
while ctx.is_open() {
// clear the context
ctx.clear(None);

// print a pixel for ever word in the video memory buffer
for x in 0..ceres_sys::SCREEN_WIDTH {
for y in 0..ceres_sys::SCREEN_HEIGHT {
let color =
@@ -46,19 +39,14 @@ fn wrapper() -> Result<()> {
}
}

// render the context
ctx.present()?;
}
*/

Ok(())
}

fn color_from_u16(color: u16) -> Color {
let r = (((color >> 8) & 0x000f) as u8) * 17;
let g = (((color >> 4) & 0x000f) as u8) * 17;
let b = ((color & 0x000f) as u8) * 17;
Color { r, g, b }
}

fn main() {
if let Err(err) = wrapper() {
eprintln!("error: {:?}", err);


+ 2
- 5
test.asm 查看文件

@@ -1,5 +1,2 @@
; a simple test application
main:
load $t0 0xcccc
load $t1 0xaaaa
sub $t0 $t1 $t3
; a simple test
ld:immd $t0 0x5a5a

正在加载...
取消
保存