2024-11-24 18:47:56 +01:00
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright (c) 2024 Patrick_Pluto
// This is an example implementation of a CPU emulator. You can copy this for your own custom ISA, or do something else.
pub struct ExampleCPU {
debug : bool ,
execution_pointer : u8 ,
operands : [ u8 ; 3 ] ,
ram : [ u8 ; 256 ] ,
registers : [ u8 ; 8 ] ,
}
impl ExampleCPU {
// Here is where you can create your own CPU Instance.
pub fn create_instance ( debug : bool , initial_state : [ u8 ; 256 ] ) -> ExampleCPU {
return ExampleCPU {
debug : debug ,
execution_pointer : 0 ,
operands : [ 0 ; 3 ] ,
ram : initial_state ,
registers : [ 0 ; 8 ] ,
} ;
}
// This fetches the operands, based on the position of the execution_pointer, then runs the selected instruction.
pub fn fetch_and_decode ( & mut self ) {
self . operands [ 0 ] = self . ram [ self . execution_pointer as usize ] ;
self . operands [ 1 ] = self . ram [ ( self . execution_pointer + 1 ) as usize ] ;
self . operands [ 2 ] = self . ram [ ( self . execution_pointer + 2 ) as usize ] ;
2024-11-24 18:49:15 +01:00
if self . debug {
println! (
" 0x{:02X} 0x{:02X} 0x{:02X} " ,
self . operands [ 0 ] , self . operands [ 1 ] , self . operands [ 2 ]
) ;
}
2024-11-24 18:47:56 +01:00
match self . operands [ 0 ] {
0x00 = > self . nop ( ) ,
0x01 = > self . load ( ) ,
0x02 = > self . store ( ) ,
0x03 = > self . add ( ) ,
0x04 = > self . sub ( ) ,
0x05 = > self . jump ( ) ,
0x06 = > self . jpiz ( ) ,
_ = > self . nop ( ) ,
} ;
}
// Here is where all of the implementations of the instructions should go.
fn nop ( & mut self ) {
self . execution_pointer + = 1 ;
}
fn load ( & mut self ) {
self . registers [ self . operands [ 1 ] as usize ] = self . ram [ self . operands [ 2 ] as usize ] ;
self . execution_pointer + = 3 ;
}
fn store ( & mut self ) {
self . ram [ self . operands [ 1 ] as usize ] = self . registers [ self . operands [ 2 ] as usize ] ;
self . execution_pointer + = 3 ;
}
fn add ( & mut self ) {
self . registers [ self . operands [ 1 ] as usize ] + = self . registers [ self . operands [ 2 ] as usize ] ;
self . execution_pointer + = 3 ;
}
fn sub ( & mut self ) {
self . registers [ self . operands [ 1 ] as usize ] - = self . registers [ self . operands [ 2 ] as usize ] ;
self . execution_pointer + = 3 ;
}
fn jump ( & mut self ) {
self . execution_pointer = self . operands [ 1 ] ;
}
fn jpiz ( & mut self ) {
if self . operands [ 2 ] = = 0 {
self . execution_pointer = self . operands [ 1 ] ;
} else {
self . execution_pointer + = 3 ;
}
}
}