Skip to content

Commit

Permalink
Implement getchar() syscall, remove read_i64()
Browse files Browse the repository at this point in the history
In response to bug pointed out in #26
  • Loading branch information
maximecb committed Sep 30, 2023
1 parent 8f2e54c commit 56a5814
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 27 deletions.
6 changes: 3 additions & 3 deletions api/syscalls.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@
"description": "Print a newline to standard output."
},
{
"name": "read_i64",
"name": "getchar",
"args": [],
"returns": [
"i64",
"i32",
"val"
],
"permission": "default_allowed",
"const_idx": 8,
"description": "Read an i64 value from standard input."
"description": "Read one byte from standard input. This is a blocking function. The value -1 is returned on end of file or error."
}
],
"constants": []
Expand Down
8 changes: 4 additions & 4 deletions doc/syscalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ void print_endl()

Print a newline to standard output.

## read_i64
## getchar

```
i64 read_i64()
i32 getchar()
```

**Returns:** `i64 val`
**Returns:** `i32 val`

Read an i64 value from standard input.
Read one byte from standard input. This is a blocking function. The value -1 is returned on end of file or error.

# time

Expand Down
6 changes: 3 additions & 3 deletions ncc/include/uvm/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
// Print a newline to standard output.
#define print_endl() asm () -> void { syscall print_endl; }

// i64 read_i64()
// Read an i64 value from standard input.
#define read_i64() asm () -> i64 { syscall read_i64; }
// i32 getchar()
// Read one byte from standard input. This is a blocking function. The value -1 is returned on end of file or error.
#define getchar() asm () -> i32 { syscall getchar; }

// u64 time_current_ms()
// Get the UNIX time stamp in milliseconds.
Expand Down
45 changes: 44 additions & 1 deletion vm/examples/factorial.asm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ push PROMPT_STR;
syscall print_str;

# Read input number
syscall read_i64;
call READ_INT, 0;

# Fall FACT with 1 argument
call FACT, 1;
Expand Down Expand Up @@ -48,3 +48,46 @@ get_arg 0;
mul_u64;

ret;

#
# Read a positive integer from stdlin
#
READ_INT:

push 0; # Current integer value

LOOP:
# Read one character
syscall getchar;

# If < 0 done
dup;
push 48;
lt_i64;
jnz DONE;

# If > 9 done
dup;
push 57;
gt_i64;
jnz DONE;

# Convert to integer digit
push 48;
sub_u64;

# int_val * 10;
get_local 0;
push 10;
mul_u64;

# int_val + 10;
add_u64;
set_local 0;

jmp LOOP;

DONE:

get_local 0;
ret;
45 changes: 44 additions & 1 deletion vm/examples/fib.asm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ push PROMPT_STR;
syscall print_str;

# Read input number
syscall read_i64;
call READ_INT, 0;

# Call FIB with 1 argument
call FIB, 1;
Expand Down Expand Up @@ -45,3 +45,46 @@ sub_u64;
call FIB, 1;
add_u64;
ret;

#
# Read a positive integer from stdlin
#
READ_INT:

push 0; # Current integer value

LOOP:
# Read one character
syscall getchar;

# If < 0 done
dup;
push 48;
lt_i64;
jnz DONE;

# If > 9 done
dup;
push 57;
gt_i64;
jnz DONE;

# Convert to integer digit
push 48;
sub_u64;

# int_val * 10;
get_local 0;
push 10;
mul_u64;

# int_val + 10;
add_u64;
set_local 0;

jmp LOOP;

DONE:

get_local 0;
ret;
45 changes: 44 additions & 1 deletion vm/examples/guess.asm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ set_local 0;
# Ask user for their guess.
push PROMPT_STR;
syscall print_str;
syscall read_i64;
call READ_INT, 0;

# if (guess == target) goto WIN;
dup;
Expand Down Expand Up @@ -85,3 +85,46 @@ syscall print_endl;

push 0;
exit;

#
# Read a positive integer from stdlin
#
READ_INT:

push 0; # Current integer value

LOOP:
# Read one character
syscall getchar;

# If < 0 done
dup;
push 48;
lt_i64;
jnz DONE;

# If > 9 done
dup;
push 57;
gt_i64;
jnz DONE;

# Convert to integer digit
push 48;
sub_u64;

# int_val * 10;
get_local 0;
push 10;
mul_u64;

# int_val + 10;
add_u64;
set_local 0;

jmp LOOP;

DONE:

get_local 0;
ret;
4 changes: 2 additions & 2 deletions vm/src/sys/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub const MEMSET: u16 = 4;
pub const PRINT_I64: u16 = 5;
pub const PRINT_STR: u16 = 6;
pub const PRINT_ENDL: u16 = 7;
pub const READ_I64: u16 = 8;
pub const GETCHAR: u16 = 8;
pub const WINDOW_ON_KEYDOWN: u16 = 9;
pub const WINDOW_DRAW_FRAME: u16 = 10;
pub const WINDOW_ON_MOUSEMOVE: u16 = 11;
Expand Down Expand Up @@ -45,7 +45,7 @@ pub const SYSCALL_DESCS: [Option<SysCallDesc>; SYSCALL_TBL_LEN] = [
Some(SysCallDesc { name: "print_i64", const_idx: 5, argc: 1, has_ret: false }),
Some(SysCallDesc { name: "print_str", const_idx: 6, argc: 1, has_ret: false }),
Some(SysCallDesc { name: "print_endl", const_idx: 7, argc: 0, has_ret: false }),
Some(SysCallDesc { name: "read_i64", const_idx: 8, argc: 0, has_ret: true }),
Some(SysCallDesc { name: "getchar", const_idx: 8, argc: 0, has_ret: true }),
Some(SysCallDesc { name: "window_on_keydown", const_idx: 9, argc: 2, has_ret: false }),
Some(SysCallDesc { name: "window_draw_frame", const_idx: 10, argc: 2, has_ret: false }),
Some(SysCallDesc { name: "window_on_mousemove", const_idx: 11, argc: 2, has_ret: false }),
Expand Down
22 changes: 10 additions & 12 deletions vm/src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod constants;
extern crate sdl2;
use std::collections::HashMap;
use std::io::Write;
use std::io::Read;
use std::io::{stdout, stdin};
use std::sync::{Arc, Weak, Mutex};
use crate::vm::{Value, VM};
Expand Down Expand Up @@ -160,7 +161,7 @@ impl SysState
self.reg_syscall(PRINT_F32, SysCallFn::Fn1_0(print_f32));
self.reg_syscall(PRINT_STR, SysCallFn::Fn1_0(print_str));
self.reg_syscall(PRINT_ENDL, SysCallFn::Fn0_0(print_endl));
self.reg_syscall(READ_I64, SysCallFn::Fn0_1(read_i64));
self.reg_syscall(GETCHAR, SysCallFn::Fn0_1(getchar));

self.reg_syscall(TIME_CURRENT_MS, SysCallFn::Fn0_1(time_current_ms));
self.reg_syscall(TIME_DELAY_CB, SysCallFn::Fn2_0(time_delay_cb));
Expand Down Expand Up @@ -232,38 +233,35 @@ fn print_i64(vm: &mut VM, v: Value)
{
let v = v.as_i64();
print!("{}", v);
stdout().flush().unwrap();
}

fn print_f32(vm: &mut VM, v: Value)
{
let v = v.as_f32();
print!("{}", v);
stdout().flush().unwrap();
}

/// Print a null-terminated UTF-8 string to stdout
fn print_str(vm: &mut VM, str_ptr: Value)
{
let rust_str = vm.get_heap_str(str_ptr.as_usize());
print!("{}", rust_str);
stdout().flush().unwrap();
}

/// Print a newline characted to stdout
fn print_endl(vm: &mut VM)
{
println!();
stdout().flush().unwrap();
}

fn read_i64(vm: &mut VM) -> Value
/// Read one byte of input from stdin.
/// Analogous to C's getchar
fn getchar(vm: &mut VM) -> Value
{
let mut line_buf = String::new();
stdin()
.read_line(&mut line_buf)
.expect("failed to read input line");
let val: i64 = line_buf.trim().parse().expect("expected i64 input");
let ch = stdin().bytes().next();

return Value::from(val);
match ch {
Some(Ok(ch)) => Value::from(ch as i64),
None | Some(Err(_)) => Value::from(-1 as i64),
}
}

0 comments on commit 56a5814

Please sign in to comment.