2021-11-09 02:19:34 +00:00
pub mod assembler ;
pub const VRAM : usize = 640 * 480 ;
pub const REGISTER_PAGE : usize = VRAM ;
pub const INPUT_PAGE : usize = VRAM + 64 ;
pub const OFFSET : usize = INPUT_PAGE ;
2021-11-13 23:27:56 +00:00
pub const MEM_SIZE : usize = 0xFFFFFF - OFFSET ;
2021-11-09 02:19:34 +00:00
pub const MEMORY : usize = OFFSET + MEM_SIZE ;
pub struct Machine {
2021-11-12 09:32:30 +00:00
pub memory : Vec < u32 > ,
2021-11-09 02:19:34 +00:00
}
impl Machine {
pub fn new ( ) -> Machine {
2021-11-12 09:32:30 +00:00
let mut memory = vec! [ 0 ; MEMORY ] ;
2021-11-09 02:19:34 +00:00
memory [ REGISTER_PAGE ] = 0x00 ;
Machine { memory }
}
2021-11-13 23:27:56 +00:00
pub fn hlt ( & self , ip : usize , instruction : u32 ) {
println! ( " --- " ) ;
println! ( " {:x} {:x} " , ip , instruction ) ;
println! (
" REG 1:{:X} 2:{:X} 3:{:X} 4:{:X} " ,
self . memory [ REGISTER_PAGE + 1 ] ,
self . memory [ REGISTER_PAGE + 2 ] ,
self . memory [ REGISTER_PAGE + 3 ] ,
self . memory [ REGISTER_PAGE + 4 ]
) ;
println! (
" REG 5:{:X} 6:{:X} 7:{:X} 8:{:X} " ,
self . memory [ REGISTER_PAGE + 5 ] ,
self . memory [ REGISTER_PAGE + 6 ] ,
self . memory [ REGISTER_PAGE + 7 ] ,
self . memory [ REGISTER_PAGE + 8 ] ,
) ;
println! (
" REG 9:{:X} A:{:X} B:{:X} C:{:X} " ,
self . memory [ REGISTER_PAGE + 9 ] ,
self . memory [ REGISTER_PAGE + 10 ] ,
self . memory [ REGISTER_PAGE + 11 ] ,
self . memory [ REGISTER_PAGE + 12 ] ,
) ;
panic! ( " hlt " )
}
2021-11-12 09:32:30 +00:00
pub fn set_keypress ( & mut self , char : u32 ) {
2021-11-12 23:37:02 +00:00
self . memory [ INPUT_PAGE + 1 ] = char
2021-11-12 09:32:30 +00:00
}
pub fn load ( & mut self , memory : Vec < u32 > ) {
2021-11-09 02:19:34 +00:00
self . memory = memory ;
self . memory [ INPUT_PAGE ] = 0x00 ;
}
2021-11-12 09:32:30 +00:00
pub fn dump ( & self ) -> Vec < u32 > {
return self . memory . clone ( ) ;
2021-11-09 02:19:34 +00:00
}
pub fn cycle ( & mut self ) {
let ip = self . memory [ REGISTER_PAGE ] as usize ;
let instruction = self . memory [ ip ] ;
self . memory [ INPUT_PAGE ] + = 1 ;
2021-11-13 23:27:56 +00:00
2021-11-09 02:19:34 +00:00
match instruction > > 28 {
0x0 = > {
match instruction > > 24 {
0x00 = > {
// NOP
}
0x01 = > {
self . memory [ REGISTER_PAGE + 63 ] = 0x01 ;
}
0x0F = > {
println! ( " --- " ) ;
println! (
" REG 1:{:X} 2:{:X} 3:{:X} 4:{:X} " ,
self . memory [ REGISTER_PAGE + 1 ] ,
self . memory [ REGISTER_PAGE + 2 ] ,
self . memory [ REGISTER_PAGE + 3 ] ,
self . memory [ REGISTER_PAGE + 4 ]
) ;
println! (
" REG 5:{:X} 6:{:X} 7:{:X} 8:{:X} " ,
self . memory [ REGISTER_PAGE + 5 ] ,
self . memory [ REGISTER_PAGE + 6 ] ,
self . memory [ REGISTER_PAGE + 7 ] ,
self . memory [ REGISTER_PAGE + 8 ] ,
) ;
println! (
" REG 9:{:X} A:{:X} B:{:X} C:{:X} " ,
self . memory [ REGISTER_PAGE + 9 ] ,
self . memory [ REGISTER_PAGE + 10 ] ,
self . memory [ REGISTER_PAGE + 11 ] ,
self . memory [ REGISTER_PAGE + 12 ] ,
) ;
panic! ( " HLT " ) ;
}
2021-11-12 09:32:30 +00:00
0x04 = > {
2021-11-12 23:37:02 +00:00
for i in 0 .. VRAM {
2021-11-12 09:32:30 +00:00
self . memory [ i ] = 0x00 ;
}
self . memory [ REGISTER_PAGE + 63 ] = 0x00 ;
}
0x07 = > {
let addr = ( instruction & 0x00FFFFFF ) as usize ;
2021-11-12 23:37:02 +00:00
let ptr = ( self . memory [ addr + 1 ] ) as usize ;
2021-11-12 09:32:30 +00:00
if ptr > 0 {
2021-11-12 23:37:02 +00:00
self . memory [ addr + 1 ] - = 1 ;
self . memory [ addr + 2 + ptr - 1 ] = 0x00 ;
2021-11-15 00:49:45 +00:00
self . memory [ addr + 2 + ptr - 1 ] = 0x00 ;
2021-11-12 09:32:30 +00:00
}
}
2021-11-09 02:19:34 +00:00
op = > {
unimplemented! ( " 0x0 Meta Instruction {} " , op )
}
}
}
0x1 = > {
// STORE R(X) => ADDR
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let mem = instruction & 0x00FFFFFF ;
self . memory [ mem as usize ] = self . memory [ REGISTER_PAGE + input_reg ] ;
}
0x2 = > {
// LOAD ADDR => R(X)
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE + input_reg ] = self . memory [ mem as usize ] ;
}
0x3 = > {
// LOAD IMMEDIATE => R(X)
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let imm = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE + input_reg ] = imm ;
}
0x04 = > {
// INC R(X)
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
self . memory [ REGISTER_PAGE + input_reg ] + = 1 ;
}
0x05 = > {
// DEC R(X)
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
self . memory [ REGISTER_PAGE + input_reg ] - = 1 ;
}
0x06 = > {
2021-11-15 05:29:42 +00:00
// STORE Mem[R(Addr)] = R(In)
let reg = ( instruction & 0x000000FF ) as usize ; // 4
let addr = self . memory [ REGISTER_PAGE + reg ] as usize ; // R(
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ; // C4)
// Mem(4) = R(C)
2021-11-09 02:19:34 +00:00
self . memory [ addr ] = self . memory [ REGISTER_PAGE + input_reg ] ;
}
0x07 = > {
2021-11-15 00:49:45 +00:00
// RLOAD R(X) = MEM(R(In))
2021-11-09 02:19:34 +00:00
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let reg = ( instruction & 0x000000FF ) as usize ;
self . memory [ REGISTER_PAGE + reg ] =
2021-11-13 23:27:56 +00:00
self . memory . get ( self . memory [ REGISTER_PAGE + input_reg ] as usize ) . unwrap_or_else ( | | { println! ( " could not rload: {:x} {:x} {:x} " , input_reg , reg , self . memory [ REGISTER_PAGE + input_reg ] as usize ) ; self . hlt ( ip , instruction ) ; unreachable! ( ) } ) . clone ( ) ;
2021-11-09 02:19:34 +00:00
}
0x08 = > {
// TX R(In) => R(X)
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let reg = ( instruction & 0x000000FF ) as usize ;
self . memory [ REGISTER_PAGE + input_reg ] = self . memory [ REGISTER_PAGE + reg ] ;
}
0x0A = > {
match instruction > > 24 {
// ADD A B => C
0xA1 = > {
let a_reg = ( ( instruction & 0x00FF0000 ) > > 16 ) as usize ;
let b_reg = ( ( instruction & 0x0000FF00 ) > > 8 ) as usize ;
let dest_reg = ( instruction & 0xFF ) as usize ;
let a = self . memory [ REGISTER_PAGE + a_reg ] ;
let b = self . memory [ REGISTER_PAGE + b_reg ] ;
2021-11-14 06:19:54 +00:00
let result = a . overflowing_add ( b ) ;
if result . 1 {
}
self . memory [ REGISTER_PAGE + dest_reg ] = result . 0 ;
2021-11-09 02:19:34 +00:00
}
// SUB A B => C
0xA2 = > {
let a_reg = ( ( instruction & 0x00FF0000 ) > > 16 ) as usize ;
let b_reg = ( ( instruction & 0x0000FF00 ) > > 8 ) as usize ;
let dest_reg = ( instruction & 0xFF ) as usize ;
let a = self . memory [ REGISTER_PAGE + a_reg ] ;
let b = self . memory [ REGISTER_PAGE + b_reg ] ;
2021-11-14 06:19:54 +00:00
let result = a . overflowing_sub ( b ) ;
if result . 1 {
}
self . memory [ REGISTER_PAGE + dest_reg ] = result . 0 ;
2021-11-09 02:19:34 +00:00
}
// MUL A B => C
0xA3 = > {
let a_reg = ( ( instruction & 0x00FF0000 ) > > 16 ) as usize ;
let b_reg = ( ( instruction & 0x0000FF00 ) > > 8 ) as usize ;
let dest_reg = ( instruction & 0xFF ) as usize ;
let a = self . memory [ REGISTER_PAGE + a_reg ] ;
let b = self . memory [ REGISTER_PAGE + b_reg ] ;
2021-11-14 06:19:54 +00:00
let result = a . overflowing_mul ( b ) ;
if result . 1 {
}
self . memory [ REGISTER_PAGE + dest_reg ] = result . 0 ;
2021-11-09 02:19:34 +00:00
}
// RSHIFT A >> B => C
0xA5 = > {
let source_reg = ( ( instruction & 0x00FF0000 ) > > 16 ) as usize ;
let bit_reg = ( ( instruction & 0x0000FF00 ) > > 8 ) as usize ;
let dest_reg = ( instruction & 0xFF ) as usize ;
let source = self . memory [ REGISTER_PAGE + source_reg ] ;
let bits = self . memory [ REGISTER_PAGE + bit_reg ] ;
let result = source > > bits ;
self . memory [ REGISTER_PAGE + dest_reg ] = result ;
}
// AND A & B => C
0xA6 = > {
let source_reg = ( ( instruction & 0x00FF0000 ) > > 16 ) as usize ;
let mask_reg = ( ( instruction & 0x0000FF00 ) > > 8 ) as usize ;
let dest_reg = ( instruction & 0xFF ) as usize ;
let source = self . memory [ REGISTER_PAGE + source_reg ] ;
let bits = self . memory [ REGISTER_PAGE + mask_reg ] ;
let result = source & bits ;
self . memory [ REGISTER_PAGE + dest_reg ] = result ;
}
2021-11-13 23:27:56 +00:00
// LSHIFT A << B => C
2021-11-13 06:03:26 +00:00
0xA7 = > {
let source_reg = ( ( instruction & 0x00FF0000 ) > > 16 ) as usize ;
let bit_reg = ( ( instruction & 0x0000FF00 ) > > 8 ) as usize ;
let dest_reg = ( instruction & 0xFF ) as usize ;
let source = self . memory [ REGISTER_PAGE + source_reg ] ;
let bits = self . memory [ REGISTER_PAGE + bit_reg ] ;
let result = source < < bits ;
self . memory [ REGISTER_PAGE + dest_reg ] = result ;
}
2021-11-09 02:19:34 +00:00
op = > {
unimplemented! ( " 0x0 Addition Instruction {} " , op )
}
}
}
2021-11-12 09:32:30 +00:00
0x0B = > {
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let addr = ( instruction & 0x00FFFFFF ) as usize ;
2021-11-12 23:37:02 +00:00
let max_len = ( self . memory [ addr ] ) as usize ;
2021-11-12 09:32:30 +00:00
if input_reg ! = 0 {
let max_len = ( self . memory [ addr ] ) as usize ;
2021-11-12 23:37:02 +00:00
let ptr = ( self . memory [ addr + 1 ] ) as usize ;
2021-11-12 09:32:30 +00:00
if ptr < max_len {
2021-11-12 23:37:02 +00:00
self . memory [ addr + 1 ] + = 1 ;
self . memory [ addr + 2 + ptr ] = self . memory [ REGISTER_PAGE + input_reg ] ;
}
} else {
self . memory [ addr + 1 ] = 0 ;
for ptr in 0 .. max_len {
self . memory [ addr + 1 + ptr ] = 0x00 ;
2021-11-12 09:32:30 +00:00
}
}
}
2021-11-09 02:19:34 +00:00
0x0C = > {
match instruction > > 24 {
// RET (Pops call stack and JMPs)
0xC0 = > {
let sp = self . memory [ REGISTER_PAGE + 62 ] as usize ;
self . memory [ REGISTER_PAGE ] = self . memory [ REGISTER_PAGE + 62 - sp ] ;
self . memory [ REGISTER_PAGE + 62 ] - = 1 ;
}
// CALL Addr (Pushed Addr and JMPS)
0xC1 = > {
self . memory [ REGISTER_PAGE + 62 ] + = 1 ;
let sp = self . memory [ REGISTER_PAGE + 62 ] as usize ;
self . memory [ REGISTER_PAGE + 62 - sp ] = self . memory [ REGISTER_PAGE ] ;
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE ] = mem - 1 ;
}
op = > {
unimplemented! ( " 0x0 Call Strack Instruction {} " , op )
}
}
2021-11-12 09:32:30 +00:00
}
0x0D = > {
2021-11-12 23:37:02 +00:00
let input_reg = ( ( instruction ) > > 24 & 0x0F ) as usize ;
let dest_ptr = ( instruction & 0x00FFFFFF ) as usize ;
if input_reg ! = 0 {
// Input Reg must point to a Buffer
let src_ptr = self . memory [ REGISTER_PAGE + input_reg ] as usize ;
if self . memory [ dest_ptr ] = = self . memory [ src_ptr ] {
for i in 0 .. self . memory [ dest_ptr ] as usize {
self . memory [ dest_ptr + i ] = self . memory [ src_ptr + i ]
}
} else {
panic! (
" attempt to copy buffers of different lengths {} {} " ,
self . memory [ dest_ptr ] , self . memory [ src_ptr ]
)
}
}
2021-11-09 02:19:34 +00:00
}
0x0E = > {
match instruction > > 24 {
0xE0 = > {
// Unconditional JMP
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE ] = mem - 1 ;
}
2021-11-12 09:32:30 +00:00
0xE1 = > {
// JEQ ADDR if R(1) != R(2)
if self . memory [ REGISTER_PAGE + 1 ] = = self . memory [ REGISTER_PAGE + 2 ] {
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE ] = mem - 1 ;
}
}
2021-11-09 02:19:34 +00:00
0xE2 = > {
// JEQ ADDR if R(1) != R(2)
if self . memory [ REGISTER_PAGE + 1 ] ! = self . memory [ REGISTER_PAGE + 2 ] {
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE ] = mem - 1 ;
}
}
2021-11-13 06:03:26 +00:00
0xE3 = > {
// JMP ADDR if R(1) > R(2)
if self . memory [ REGISTER_PAGE + 1 ] > self . memory [ REGISTER_PAGE + 2 ] {
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE ] = mem - 1 ;
}
}
0xE4 = > {
// JMP ADDR if R(1) > R(2)
if self . memory [ REGISTER_PAGE + 1 ] < self . memory [ REGISTER_PAGE + 2 ] {
let mem = instruction & 0x00FFFFFF ;
self . memory [ REGISTER_PAGE ] = mem - 1 ;
}
}
0xEf = > {
let mem = instruction & 0x0000FF ;
self . memory [ REGISTER_PAGE ] = self . memory [ REGISTER_PAGE + mem as usize ] - 1 ;
}
2021-11-09 02:19:34 +00:00
op = > {
unimplemented! ( " 0x0 JMP Instruction {} " , op )
}
}
}
x = > {
panic! ( " unknown bytecode opcode {:X} {:X} {:X} " , x , ip , instruction )
}
}
self . memory [ REGISTER_PAGE ] + = 1 ;
//
}
}