added serial-out support to emulator + serial lib & command line mode for dsa emulator
This commit is contained in:
@@ -0,0 +1,55 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
use crate::emulator::system::model::{Command, Running};
|
||||||
|
use crate::emulator::{config::Config, system::model::State};
|
||||||
|
|
||||||
|
pub fn run_cli() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Initialize channels and read in configuration.
|
||||||
|
let (cmd_sender, cmd_receiver) = std::sync::mpsc::channel();
|
||||||
|
let (state_sender, state_reciever) = std::sync::mpsc::channel();
|
||||||
|
|
||||||
|
// not needed for now.
|
||||||
|
// let config = Config::load(Path::new(".dsa.emulator.toml"))?;
|
||||||
|
|
||||||
|
crate::setup_emulator(cmd_receiver, state_sender, None);
|
||||||
|
|
||||||
|
// run CLI.
|
||||||
|
let mut state = State::new(cmd_sender, state_reciever);
|
||||||
|
|
||||||
|
let mut bin_path: Option<String> = None;
|
||||||
|
for (i, arg) in env::args().enumerate().skip(1) {
|
||||||
|
// check for args --bin and <bin_path>
|
||||||
|
if arg == "--bin" {
|
||||||
|
bin_path = Some(env::args().nth(i + 1).expect("Binary path not provided"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let binary =
|
||||||
|
fs::read(bin_path.expect("unreachable")).expect("unable to read binary file");
|
||||||
|
state.send(Command::Write(0, binary));
|
||||||
|
println!("{:?}", state.running);
|
||||||
|
|
||||||
|
sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
|
state.update().unwrap();
|
||||||
|
state.cmd_sender.send(Command::Start).unwrap();
|
||||||
|
loop {
|
||||||
|
sleep(Duration::from_millis(20));
|
||||||
|
state.send(Command::DisplayRequest);
|
||||||
|
state.send(Command::RunningRequest);
|
||||||
|
state.update().expect("update failed");
|
||||||
|
|
||||||
|
for ch in state.serial_buff.drain(..) {
|
||||||
|
print!("{}", ch as char);
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.running == Running::Halted {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod cli;
|
||||||
#[cfg(feature = "config")]
|
#[cfg(feature = "config")]
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub const DISPLAY_ADDRESS: u32 = 0x20000;
|
||||||
|
pub const SERIAL_ADDRESS: u32 = DISPLAY_ADDRESS + 2000;
|
||||||
@@ -135,6 +135,9 @@ pub fn run_emulator(
|
|||||||
Vec::new()
|
Vec::new()
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
let _ = state_tx.send(StateUpdate::Serial(
|
||||||
|
processor.serial_buff.drain(..).collect(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Command::StackRequest if update => {
|
Command::StackRequest if update => {
|
||||||
let _ = state_tx.send(StateUpdate::StackView(
|
let _ = state_tx.send(StateUpdate::StackView(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
pub mod constants;
|
||||||
pub mod emulator;
|
pub mod emulator;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pub enum Command {
|
|||||||
WriteBlock(Address, Box<[u8; 256]>),
|
WriteBlock(Address, Box<[u8; 256]>),
|
||||||
|
|
||||||
// request emulator state.
|
// request emulator state.
|
||||||
|
SerialRequest,
|
||||||
MemRequest(Address, u32),
|
MemRequest(Address, u32),
|
||||||
DisplayRequest,
|
DisplayRequest,
|
||||||
StackRequest,
|
StackRequest,
|
||||||
@@ -79,6 +80,7 @@ pub struct State {
|
|||||||
pub error_log: Vec<String>,
|
pub error_log: Vec<String>,
|
||||||
|
|
||||||
pub instruction_history: Vec<(u32, u32)>,
|
pub instruction_history: Vec<(u32, u32)>,
|
||||||
|
pub serial_buff: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@@ -95,6 +97,7 @@ impl State {
|
|||||||
display_view: vec![],
|
display_view: vec![],
|
||||||
error_log: vec![],
|
error_log: vec![],
|
||||||
instruction_history: vec![],
|
instruction_history: vec![],
|
||||||
|
serial_buff: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +124,9 @@ impl State {
|
|||||||
StateUpdate::InstructionHistory(history) => {
|
StateUpdate::InstructionHistory(history) => {
|
||||||
self.instruction_history.extend(history);
|
self.instruction_history.extend(history);
|
||||||
}
|
}
|
||||||
|
StateUpdate::Serial(buffer) => {
|
||||||
|
self.serial_buff.extend(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.error_log.len() > 256 {
|
if self.error_log.len() > 256 {
|
||||||
@@ -148,6 +154,7 @@ impl State {
|
|||||||
|
|
||||||
pub enum StateUpdate {
|
pub enum StateUpdate {
|
||||||
Registers(RegFile),
|
Registers(RegFile),
|
||||||
|
Serial(Vec<u8>),
|
||||||
Running(Running),
|
Running(Running),
|
||||||
Instructions(usize),
|
Instructions(usize),
|
||||||
StackView(Vec<u8>),
|
StackView(Vec<u8>),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::{
|
|||||||
|
|
||||||
use crate::emulator::system::{
|
use crate::emulator::system::{
|
||||||
cache::Cache,
|
cache::Cache,
|
||||||
|
constants::{DISPLAY_ADDRESS, SERIAL_ADDRESS},
|
||||||
memory::MemoryUnit,
|
memory::MemoryUnit,
|
||||||
model::{IODevice, ProcessorError, RegFile},
|
model::{IODevice, ProcessorError, RegFile},
|
||||||
};
|
};
|
||||||
@@ -19,6 +20,8 @@ pub struct Processor {
|
|||||||
|
|
||||||
pub void: u32,
|
pub void: u32,
|
||||||
pub cache: Cache,
|
pub cache: Cache,
|
||||||
|
|
||||||
|
pub serial_buff: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Processor {
|
impl Processor {
|
||||||
@@ -31,6 +34,8 @@ impl Processor {
|
|||||||
io_devices,
|
io_devices,
|
||||||
void: 0,
|
void: 0,
|
||||||
cache: Cache::new(),
|
cache: Cache::new(),
|
||||||
|
|
||||||
|
serial_buff: Vec::with_capacity(32768),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +102,7 @@ impl Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn display(&mut self) -> Result<Vec<u8>, ProcessorError> {
|
pub fn display(&mut self) -> Result<Vec<u8>, ProcessorError> {
|
||||||
Ok(self.memory.read_range(0x20000, 2000))
|
Ok(self.memory.read_range(DISPLAY_ADDRESS, 2000))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmp(&mut self, a: u32, b: u32) {
|
pub fn cmp(&mut self, a: u32, b: u32) {
|
||||||
@@ -267,30 +272,41 @@ impl Executable for Instruction {
|
|||||||
// Stores a byte from SrcReg in memory address (base + offset) The effective
|
// Stores a byte from SrcReg in memory address (base + offset) The effective
|
||||||
// address must be byte-aligned.
|
// address must be byte-aligned.
|
||||||
Self::StoreByte(a) => {
|
Self::StoreByte(a) => {
|
||||||
cpu.memory.write_byte(
|
let addr = cpu.get(a.r2)? + u32::from(a.immediate);
|
||||||
cpu.get(a.r2)? + u32::from(a.immediate),
|
let val = cpu.get(a.r1)? as u8;
|
||||||
cpu.get(a.r1)? as u8,
|
if addr == SERIAL_ADDRESS {
|
||||||
);
|
cpu.serial_buff.push(val);
|
||||||
|
}
|
||||||
|
cpu.memory.write_byte(addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores a half-word from SrcReg in memory address (base + offset) The
|
// Stores a half-word from SrcReg in memory address (base + offset) The
|
||||||
// effective address must be 2-byte-aligned.
|
// effective address must be 2-byte-aligned.
|
||||||
Self::StoreHalfword(a) => {
|
Self::StoreHalfword(a) => {
|
||||||
// split the value into bytes and then write two bytes
|
let addr = cpu.get(a.r2)? + u32::from(a.immediate);
|
||||||
let bytes = (cpu.get(a.r1)? as u16).to_le_bytes();
|
let bytes = (cpu.get(a.r1)? as u16).to_le_bytes();
|
||||||
cpu.memory
|
|
||||||
.write_byte(cpu.get(a.r2)? + u32::from(a.immediate), bytes[0]);
|
if addr == SERIAL_ADDRESS {
|
||||||
cpu.memory
|
cpu.serial_buff.extend(bytes);
|
||||||
.write_byte(cpu.get(a.r2)? + u32::from(a.immediate) + 1, bytes[1]);
|
}
|
||||||
|
|
||||||
|
// split the value into bytes and then write two bytes
|
||||||
|
cpu.memory.write_byte(addr, bytes[0]);
|
||||||
|
cpu.memory.write_byte(addr + 1, bytes[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores a word from SrcReg in memory address (base + offset) The effective
|
// Stores a word from SrcReg in memory address (base + offset) The effective
|
||||||
// address must be 4-byte-aligned.
|
// address must be 4-byte-aligned.
|
||||||
Self::StoreWord(a) => {
|
Self::StoreWord(a) => {
|
||||||
cpu.memory.write_word(
|
let addr = cpu.get(a.r2)? + u32::from(a.immediate);
|
||||||
cpu.get(a.r2)? + u32::from(a.immediate),
|
let val = cpu.get(a.r1)?;
|
||||||
cpu.get(a.r1)?,
|
let bytes = val.to_le_bytes();
|
||||||
)?;
|
|
||||||
|
if addr == SERIAL_ADDRESS {
|
||||||
|
cpu.serial_buff.extend(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu.memory.write_word(addr, val)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads a 16-bit literal value into reg, setting the bottom 16 bits of the
|
// Loads a 16-bit literal value into reg, setting the bottom 16 bits of the
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut assembler = Assembler::new(&dsa_path);
|
let mut assembler = Assembler::new(&dsa_path);
|
||||||
compiler.start();
|
assembler.start();
|
||||||
|
|
||||||
// Or block until done
|
// Or block until done
|
||||||
self.output = match assembler.output() {
|
self.output = match assembler.output() {
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use dsa_rs::emulator::{config::Config, misc::rpc::get_rpc_client_or_none};
|
use dsa_rs::emulator::{config::Config, misc::rpc::get_rpc_client_or_none};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if env::args().any(|arg| arg == "--cli") {
|
||||||
|
dsa_rs::emulator::cli::run_cli()?;
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize channels and read in configuration.
|
// Initialize channels and read in configuration.
|
||||||
let (cmd_sender, cmd_receiver) = std::sync::mpsc::channel();
|
let (cmd_sender, cmd_receiver) = std::sync::mpsc::channel();
|
||||||
let (state_sender, state_reciever) = std::sync::mpsc::channel();
|
let (state_sender, state_reciever) = std::sync::mpsc::channel();
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
// lib:
|
||||||
|
// print_serial.dsa
|
||||||
|
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print_serial "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print
|
||||||
|
//
|
||||||
|
// usage for print_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_byte
|
||||||
|
//
|
||||||
|
// usage for print_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_word
|
||||||
|
//
|
||||||
|
// usage for print_hex_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_hex_byte
|
||||||
|
//
|
||||||
|
// usage for print_hex_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_hex_word
|
||||||
|
//
|
||||||
|
// usage for print_num:
|
||||||
|
// push (register containing number to print in decimal)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_num
|
||||||
|
//
|
||||||
|
// usage for println:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::println
|
||||||
|
//
|
||||||
|
|
||||||
|
include maths "../maths/core.dsa"
|
||||||
|
|
||||||
|
dw serial: 0x207D0 // 0x20000 + 2000
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) to the serial port.
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
jmp _print_loop
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) followed by a newline to the serial port.
|
||||||
|
println:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_println_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _println_end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
jmp _println_loop
|
||||||
|
|
||||||
|
_println_end:
|
||||||
|
lli 0x0A, rg2 // newline character
|
||||||
|
stb rg2, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the word in arg[0] as 4 raw bytes to the serial port.
|
||||||
|
print_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the serial port.
|
||||||
|
print_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the serial port in hex.
|
||||||
|
print_hex_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
ldb bpr, rg0, 8
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 9
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 10
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 11
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the serial port in hex.
|
||||||
|
print_hex_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
call _print_hex_byte
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// function body
|
||||||
|
_print_hex_byte:
|
||||||
|
lli 0xF, rg2
|
||||||
|
push rg0
|
||||||
|
|
||||||
|
shr rg0, 4
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
pop rg0
|
||||||
|
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
return
|
||||||
|
|
||||||
|
// print a hex digit
|
||||||
|
_print_hex_nibble:
|
||||||
|
lli 10, rg3
|
||||||
|
cmp rg0, rg3
|
||||||
|
jlt _print_hex_nibble_number
|
||||||
|
addi rg0, 0x37, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
return
|
||||||
|
|
||||||
|
_print_hex_nibble_number:
|
||||||
|
addi rg0, 0x30, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
return
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints arg[0] as a decimal number to the serial port.
|
||||||
|
print_num:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lli 0, rg5
|
||||||
|
|
||||||
|
cmp rg0, zero
|
||||||
|
jne _print_num_extract_digits
|
||||||
|
|
||||||
|
lli 0x30, rg6
|
||||||
|
push rg6
|
||||||
|
lli 1, rg5
|
||||||
|
jmp _print_num_output
|
||||||
|
|
||||||
|
_print_num_extract_digits:
|
||||||
|
cmp rg0, zero
|
||||||
|
jeq _print_num_output
|
||||||
|
|
||||||
|
push rg0
|
||||||
|
lli 10, rg1
|
||||||
|
push rg1
|
||||||
|
call maths::divmod
|
||||||
|
pop rg0
|
||||||
|
pop rg1
|
||||||
|
|
||||||
|
addi rg1, 0x30, rg6
|
||||||
|
push rg6
|
||||||
|
inc rg5
|
||||||
|
|
||||||
|
jmp _print_num_extract_digits
|
||||||
|
|
||||||
|
_print_num_output:
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_print_num_output_loop:
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _print_num_done
|
||||||
|
|
||||||
|
pop rg6
|
||||||
|
stb rg6, rg1
|
||||||
|
dec rg5
|
||||||
|
|
||||||
|
jmp _print_num_output_loop
|
||||||
|
|
||||||
|
_print_num_done:
|
||||||
|
// fall through to _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// return
|
||||||
|
_end:
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
+140
-9
@@ -1,12 +1,143 @@
|
|||||||
// program to just test compute power
|
// GENERATED BY DSC COMPILER
|
||||||
|
// Generated at 2026-02-23 17:29:47
|
||||||
|
|
||||||
dw large_num: 0x333333 // 333,333 instructions
|
// Imports
|
||||||
start:
|
include print: "./lib/io/print.dsa"
|
||||||
ldw large_num, rg0
|
include alloc: "./lib/memory/block_alloc.dsa"
|
||||||
|
|
||||||
// run approx 1m instructions
|
// Globals & Reserved Memory
|
||||||
loop:
|
|
||||||
dec rg0
|
// Entry Point
|
||||||
cmp rg0, zero
|
dw stack: 0x010000
|
||||||
jgt loop
|
db message: "Process Exited with code:"
|
||||||
|
_init:
|
||||||
|
ldw stack, bpr, 0
|
||||||
|
mov bpr, spr
|
||||||
|
push zero
|
||||||
|
call main
|
||||||
|
call print::print_newline
|
||||||
|
lwi message, rg0
|
||||||
|
push rg0
|
||||||
|
call print::print
|
||||||
|
pop zero
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
hlt
|
hlt
|
||||||
|
|
||||||
|
// Return
|
||||||
|
_ret:
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
db str_16: "successful free of ptr"
|
||||||
|
// fn main() -> u32
|
||||||
|
main:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
lli 32, rg0
|
||||||
|
lli 64, rg1
|
||||||
|
// push arg 1
|
||||||
|
push rg0
|
||||||
|
// push arg 0
|
||||||
|
push rg1
|
||||||
|
call alloc::init
|
||||||
|
pop rg2
|
||||||
|
pop zero
|
||||||
|
push rg2
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
call print::print_newline
|
||||||
|
ldw spr, rg0, 0
|
||||||
|
stw rg0, spr, 0
|
||||||
|
// push arg 0
|
||||||
|
push rg0
|
||||||
|
call alloc::alloc
|
||||||
|
pop rg1
|
||||||
|
push rg1
|
||||||
|
// push arg 0
|
||||||
|
push rg1
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
lli 200, rg0
|
||||||
|
ldw spr, rg1, 0
|
||||||
|
stw rg0, rg1, 0
|
||||||
|
stw rg1, spr, 0
|
||||||
|
call print::print_newline
|
||||||
|
ldw spr, rg0, 4
|
||||||
|
stw rg0, spr, 4
|
||||||
|
// push arg 0
|
||||||
|
push rg0
|
||||||
|
call alloc::alloc
|
||||||
|
pop rg2
|
||||||
|
push rg2
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
call print::print_newline
|
||||||
|
ldw spr, rg0, 4
|
||||||
|
ldw rg0, rg2, 0
|
||||||
|
stw rg0, spr, 4
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call print::print_num
|
||||||
|
pop zero
|
||||||
|
ldw spr, rg2, 4
|
||||||
|
stw rg2, spr, 4
|
||||||
|
addi spr, 4, rg3
|
||||||
|
ldw spr, rg2, 8
|
||||||
|
stw rg2, spr, 8
|
||||||
|
// push arg 1
|
||||||
|
push rg3
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call alloc::free
|
||||||
|
pop zero
|
||||||
|
pop zero
|
||||||
|
ldw spr, rg2, 8
|
||||||
|
stw rg2, spr, 8
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call alloc::alloc
|
||||||
|
pop rg3
|
||||||
|
push rg3
|
||||||
|
call print::print_newline
|
||||||
|
ldw spr, rg2, 0
|
||||||
|
stw rg2, spr, 0
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
call print::print_newline
|
||||||
|
ldw spr, rg2, 8
|
||||||
|
stw rg2, spr, 8
|
||||||
|
// push arg 0
|
||||||
|
push rg2
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
ldw spr, rg2, 8
|
||||||
|
lli 0, rg4
|
||||||
|
cmp rg2, rg4
|
||||||
|
lli 1, rg5
|
||||||
|
jeq _cmp_end_12
|
||||||
|
lli 0, rg5
|
||||||
|
_cmp_end_12:
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _else_14
|
||||||
|
_then_13:
|
||||||
|
lwi str_16, rg4
|
||||||
|
stw rg2, spr, 8
|
||||||
|
// push arg 0
|
||||||
|
push rg4
|
||||||
|
call print::print
|
||||||
|
pop zero
|
||||||
|
jmp _end_15
|
||||||
|
_else_14:
|
||||||
|
nop
|
||||||
|
_end_15:
|
||||||
|
lli 0, rg4
|
||||||
|
stw rg4, bpr, 8
|
||||||
|
jmp _ret
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
name = "test"
|
||||||
|
binaries = []
|
||||||
Binary file not shown.
@@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
// multiply.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include multiply "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for multiply:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load op 2
|
||||||
|
ldw bpr, rg1, 12 // load op 1
|
||||||
|
lwi 0, rg2 // initialise rg2 to zero
|
||||||
|
|
||||||
|
_multiply_loop:
|
||||||
|
add rg2, rg0, rg2
|
||||||
|
dec rg1
|
||||||
|
|
||||||
|
cmp rg1, zero
|
||||||
|
jgt _multiply_loop
|
||||||
|
|
||||||
|
_multiply_end:
|
||||||
|
stw rg2, bpr, 8
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
divmod:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg1, 8 // load op 2
|
||||||
|
ldw bpr, rg0, 12 // load op 1
|
||||||
|
|
||||||
|
lli 0, rg3
|
||||||
|
|
||||||
|
_divmod_loop:
|
||||||
|
cmp rg0, rg1
|
||||||
|
jlt _divmod_end
|
||||||
|
|
||||||
|
sub rg0, rg1, rg0
|
||||||
|
inc rg3
|
||||||
|
|
||||||
|
jmp _divmod_loop
|
||||||
|
|
||||||
|
_divmod_end:
|
||||||
|
// store div in first arg
|
||||||
|
// store mod in second arg
|
||||||
|
stw rg3, bpr, 8
|
||||||
|
stw rg0, bpr, 12
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
// multiply.dsa - improved version
|
||||||
|
// Multiplies two 32-bit numbers using shift-and-add
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// push operand2 (multiplier)
|
||||||
|
// push operand1 (multiplicand)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop result
|
||||||
|
// pop zero (discard second argument)
|
||||||
|
|
||||||
|
new_multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // rg0 = multiplicand
|
||||||
|
ldw bpr, rg1, 12 // rg1 = multiplier
|
||||||
|
|
||||||
|
lli 0, rg2 // rg2 = result (accumulator)
|
||||||
|
lli 32, rg3 // rg3 = bit counter
|
||||||
|
|
||||||
|
mult_loop:
|
||||||
|
// Check if lowest bit of multiplier is 1
|
||||||
|
lli 1, acc
|
||||||
|
and rg1, acc, acc // acc = rg1 & 1
|
||||||
|
cmp acc, zero
|
||||||
|
jeq skip_add // if (rg1 & 1) == 0, skip addition
|
||||||
|
|
||||||
|
// Add multiplicand to result
|
||||||
|
add rg2, rg0, rg2
|
||||||
|
|
||||||
|
skip_add:
|
||||||
|
shl rg0, 1 // shift multiplicand left
|
||||||
|
shr rg1, 1 // shift multiplier right
|
||||||
|
|
||||||
|
dec rg3
|
||||||
|
cmp rg3, zero
|
||||||
|
jgt mult_loop
|
||||||
|
|
||||||
|
stw rg2, bpr, 8 // store result
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
|
||||||
|
// lib:
|
||||||
|
// print.dsa
|
||||||
|
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print "<relative path>""
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print
|
||||||
|
//
|
||||||
|
// usage for reset:
|
||||||
|
// push pcx
|
||||||
|
// jmp print::reset
|
||||||
|
//
|
||||||
|
// usage for clear:
|
||||||
|
// push pcx
|
||||||
|
// jmp print::clear
|
||||||
|
//
|
||||||
|
// usage for print_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_byte
|
||||||
|
//
|
||||||
|
// usage for print_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_word
|
||||||
|
//
|
||||||
|
// usage for print_num:
|
||||||
|
// push (register containing number to print in decimal)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_num
|
||||||
|
//
|
||||||
|
|
||||||
|
include maths "./maths.dsa"
|
||||||
|
|
||||||
|
dw display: 0x20000
|
||||||
|
dw current: 0x20000
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) to the screen. (no trailing whitespace unless explicitly provided)
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
_print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
addi rg1, 1
|
||||||
|
|
||||||
|
jmp _print_loop
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
println:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
_println_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _println_end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
addi rg1, 1
|
||||||
|
|
||||||
|
jmp _println_loop
|
||||||
|
|
||||||
|
_println_end:
|
||||||
|
call print_newline
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the screen.
|
||||||
|
print_word:
|
||||||
|
// initialise
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// load byte into acc
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
addi rg1, 3
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
|
||||||
|
addi rg1, 4
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the screen.
|
||||||
|
print_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the screen in hex.
|
||||||
|
print_hex_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
ldb bpr, rg0, 8
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 9
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 10
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 11
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the screen in hex.
|
||||||
|
print_hex_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
call _print_hex_byte
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// function body
|
||||||
|
_print_hex_byte:
|
||||||
|
// mask to get lower nibble
|
||||||
|
lli 0xF, rg2
|
||||||
|
// save rg0 state
|
||||||
|
push rg0
|
||||||
|
|
||||||
|
shr rg0, 4
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
pop rg0
|
||||||
|
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
return
|
||||||
|
|
||||||
|
// print a hex digit
|
||||||
|
_print_hex_nibble:
|
||||||
|
lli 10, rg3
|
||||||
|
cmp rg0, rg3
|
||||||
|
jlt _print_hex_nibble_number
|
||||||
|
addi rg0, 0x37, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
return
|
||||||
|
|
||||||
|
// helper function.
|
||||||
|
_print_hex_nibble_number:
|
||||||
|
addi rg0, 0x30, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
return
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// print whitespace
|
||||||
|
print_whitespace:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw current, rg1
|
||||||
|
lli 0x20, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// print newline
|
||||||
|
print_newline:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// load variables into registers
|
||||||
|
ldw display, rg0
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
// get the offset from the display base
|
||||||
|
sub rg1, rg0, rg0
|
||||||
|
|
||||||
|
lwi 80, rg2
|
||||||
|
pusha 3
|
||||||
|
push rg0
|
||||||
|
push rg2
|
||||||
|
call maths::divmod
|
||||||
|
pop zero // result
|
||||||
|
pop rg3 // remainder
|
||||||
|
popa 3
|
||||||
|
|
||||||
|
sub rg1, rg3, rg2
|
||||||
|
addi rg2, 80, rg1
|
||||||
|
|
||||||
|
// _end saves the display state
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints arg[0] as a decimal number to the screen.
|
||||||
|
print_num:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load number to print
|
||||||
|
lli 0, rg5 // rg5 = digit counter
|
||||||
|
|
||||||
|
// check if number is zero
|
||||||
|
cmp rg0, zero
|
||||||
|
jne _print_num_extract_digits
|
||||||
|
|
||||||
|
// special case: print '0' for zero
|
||||||
|
lli 0x30, rg6
|
||||||
|
push rg6 // push digit to stack buffer
|
||||||
|
lli 1, rg5 // we have 1 digit
|
||||||
|
jmp _print_num_output
|
||||||
|
|
||||||
|
_print_num_extract_digits:
|
||||||
|
// divide by 10 repeatedly to get digits
|
||||||
|
cmp rg0, zero
|
||||||
|
jeq _print_num_output
|
||||||
|
|
||||||
|
// call divmod(rg0, 10)
|
||||||
|
push rg0 // dividend
|
||||||
|
lli 10, rg1
|
||||||
|
push rg1 // divisor (10)
|
||||||
|
call maths::divmod
|
||||||
|
pop rg0 // quotient (continue dividing this)
|
||||||
|
pop rg1 // remainder (the digit)
|
||||||
|
|
||||||
|
// convert digit to ASCII and push to stack buffer
|
||||||
|
addi rg1, 0x30, rg6 // convert to ASCII
|
||||||
|
push rg6 // push digit to stack
|
||||||
|
inc rg5 // increment digit counter
|
||||||
|
|
||||||
|
jmp _print_num_extract_digits
|
||||||
|
|
||||||
|
_print_num_output:
|
||||||
|
// now print digits (pop them off in reverse order)
|
||||||
|
ldw current, rg1 // get display pointer
|
||||||
|
|
||||||
|
_print_num_output_loop:
|
||||||
|
// check if we've printed all digits
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _print_num_done
|
||||||
|
|
||||||
|
// pop digit and print it
|
||||||
|
pop rg6
|
||||||
|
stb rg6, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
dec rg5
|
||||||
|
|
||||||
|
jmp _print_num_output_loop
|
||||||
|
|
||||||
|
_print_num_done:
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// resets the cursor position on the screen to 0x20000. (0,0)
|
||||||
|
reset:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
ldw display, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// clears the screen
|
||||||
|
clear:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
// display size = 2000 bytes / 500 words
|
||||||
|
lli 500 rg0
|
||||||
|
ldw display, rg1
|
||||||
|
|
||||||
|
_clear_loop:
|
||||||
|
dec rg0
|
||||||
|
stw zero, rg1
|
||||||
|
addi rg1, 4
|
||||||
|
cmp rg0, zero
|
||||||
|
jgt _clear_loop
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// return
|
||||||
|
_end:
|
||||||
|
stw rg1, current
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
// lib:
|
||||||
|
// print_serial.dsa
|
||||||
|
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print_serial "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print
|
||||||
|
//
|
||||||
|
// usage for print_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_byte
|
||||||
|
//
|
||||||
|
// usage for print_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_word
|
||||||
|
//
|
||||||
|
// usage for print_hex_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_hex_byte
|
||||||
|
//
|
||||||
|
// usage for print_hex_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_hex_word
|
||||||
|
//
|
||||||
|
// usage for print_num:
|
||||||
|
// push (register containing number to print in decimal)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_num
|
||||||
|
//
|
||||||
|
// usage for println:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::println
|
||||||
|
//
|
||||||
|
|
||||||
|
include maths "./maths.dsa"
|
||||||
|
|
||||||
|
dw serial: 0x207D0 // 0x20000 + 2000
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) to the serial port.
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
jmp _print_loop
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) followed by a newline to the serial port.
|
||||||
|
println:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_println_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _println_end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
jmp _println_loop
|
||||||
|
|
||||||
|
_println_end:
|
||||||
|
lli 0x0A, rg2 // newline character
|
||||||
|
stb rg2, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the word in arg[0] as 4 raw bytes to the serial port.
|
||||||
|
print_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the serial port.
|
||||||
|
print_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the serial port in hex.
|
||||||
|
print_hex_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
ldb bpr, rg0, 8
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 9
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 10
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 11
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the serial port in hex.
|
||||||
|
print_hex_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
call _print_hex_byte
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// function body
|
||||||
|
_print_hex_byte:
|
||||||
|
lli 0xF, rg2
|
||||||
|
push rg0
|
||||||
|
|
||||||
|
shr rg0, 4
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
pop rg0
|
||||||
|
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
return
|
||||||
|
|
||||||
|
// print a hex digit
|
||||||
|
_print_hex_nibble:
|
||||||
|
lli 10, rg3
|
||||||
|
cmp rg0, rg3
|
||||||
|
jlt _print_hex_nibble_number
|
||||||
|
addi rg0, 0x37, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
return
|
||||||
|
|
||||||
|
_print_hex_nibble_number:
|
||||||
|
addi rg0, 0x30, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
return
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints arg[0] as a decimal number to the serial port.
|
||||||
|
print_num:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lli 0, rg5
|
||||||
|
|
||||||
|
cmp rg0, zero
|
||||||
|
jne _print_num_extract_digits
|
||||||
|
|
||||||
|
lli 0x30, rg6
|
||||||
|
push rg6
|
||||||
|
lli 1, rg5
|
||||||
|
jmp _print_num_output
|
||||||
|
|
||||||
|
_print_num_extract_digits:
|
||||||
|
cmp rg0, zero
|
||||||
|
jeq _print_num_output
|
||||||
|
|
||||||
|
push rg0
|
||||||
|
lli 10, rg1
|
||||||
|
push rg1
|
||||||
|
call maths::divmod
|
||||||
|
pop rg0
|
||||||
|
pop rg1
|
||||||
|
|
||||||
|
addi rg1, 0x30, rg6
|
||||||
|
push rg6
|
||||||
|
inc rg5
|
||||||
|
|
||||||
|
jmp _print_num_extract_digits
|
||||||
|
|
||||||
|
_print_num_output:
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_print_num_output_loop:
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _print_num_done
|
||||||
|
|
||||||
|
pop rg6
|
||||||
|
stb rg6, rg1
|
||||||
|
dec rg5
|
||||||
|
|
||||||
|
jmp _print_num_output_loop
|
||||||
|
|
||||||
|
_print_num_done:
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// return
|
||||||
|
_end:
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// GENERATED BY DSC COMPILER
|
||||||
|
// Generated at 2026-02-23 18:58:53
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
include print: "./lib/print.dsa"
|
||||||
|
|
||||||
|
// Globals & Reserved Memory
|
||||||
|
|
||||||
|
// Entry Point
|
||||||
|
dw stack: 0x010000
|
||||||
|
db message: "Process Exited with code:"
|
||||||
|
_init:
|
||||||
|
ldw stack, bpr, 0
|
||||||
|
mov bpr, spr
|
||||||
|
push zero
|
||||||
|
call main
|
||||||
|
call print::print_newline
|
||||||
|
lwi message, rg0
|
||||||
|
push rg0
|
||||||
|
call print::print
|
||||||
|
pop zero
|
||||||
|
call print::print_hex_word
|
||||||
|
pop zero
|
||||||
|
hlt
|
||||||
|
|
||||||
|
// Return
|
||||||
|
_ret:
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
db str_1: "Hello, World!"
|
||||||
|
// fn main() -> void
|
||||||
|
main:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
lwi str_1, rg0
|
||||||
|
// push arg 0
|
||||||
|
push rg0
|
||||||
|
call print::print
|
||||||
|
pop zero
|
||||||
|
jmp _ret
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
include print: "./lib/print.dsa";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
print::print("Hello, World!");
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
|
||||||
|
// multiply.dsa
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include multiply "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for multiply:
|
||||||
|
// push (arg1)
|
||||||
|
// push (arg0)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop (arg0)
|
||||||
|
// pop (arg1)
|
||||||
|
|
||||||
|
multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load op 2
|
||||||
|
ldw bpr, rg1, 12 // load op 1
|
||||||
|
lwi 0, rg2 // initialise rg2 to zero
|
||||||
|
|
||||||
|
_multiply_loop:
|
||||||
|
add rg2, rg0, rg2
|
||||||
|
dec rg1
|
||||||
|
|
||||||
|
cmp rg1, zero
|
||||||
|
jgt _multiply_loop
|
||||||
|
|
||||||
|
_multiply_end:
|
||||||
|
stw rg2, bpr, 8
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
divmod:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg1, 8 // load op 2
|
||||||
|
ldw bpr, rg0, 12 // load op 1
|
||||||
|
|
||||||
|
lli 0, rg3
|
||||||
|
|
||||||
|
_divmod_loop:
|
||||||
|
cmp rg0, rg1
|
||||||
|
jlt _divmod_end
|
||||||
|
|
||||||
|
sub rg0, rg1, rg0
|
||||||
|
inc rg3
|
||||||
|
|
||||||
|
jmp _divmod_loop
|
||||||
|
|
||||||
|
_divmod_end:
|
||||||
|
// store div in first arg
|
||||||
|
// store mod in second arg
|
||||||
|
stw rg3, bpr, 8
|
||||||
|
stw rg0, bpr, 12
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
|
|
||||||
|
// multiply.dsa - improved version
|
||||||
|
// Multiplies two 32-bit numbers using shift-and-add
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// push operand2 (multiplier)
|
||||||
|
// push operand1 (multiplicand)
|
||||||
|
// call multiply::multiply
|
||||||
|
// pop result
|
||||||
|
// pop zero (discard second argument)
|
||||||
|
|
||||||
|
new_multiply:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // rg0 = multiplicand
|
||||||
|
ldw bpr, rg1, 12 // rg1 = multiplier
|
||||||
|
|
||||||
|
lli 0, rg2 // rg2 = result (accumulator)
|
||||||
|
lli 32, rg3 // rg3 = bit counter
|
||||||
|
|
||||||
|
mult_loop:
|
||||||
|
// Check if lowest bit of multiplier is 1
|
||||||
|
lli 1, acc
|
||||||
|
and rg1, acc, acc // acc = rg1 & 1
|
||||||
|
cmp acc, zero
|
||||||
|
jeq skip_add // if (rg1 & 1) == 0, skip addition
|
||||||
|
|
||||||
|
// Add multiplicand to result
|
||||||
|
add rg2, rg0, rg2
|
||||||
|
|
||||||
|
skip_add:
|
||||||
|
shl rg0, 1 // shift multiplicand left
|
||||||
|
shr rg1, 1 // shift multiplier right
|
||||||
|
|
||||||
|
dec rg3
|
||||||
|
cmp rg3, zero
|
||||||
|
jgt mult_loop
|
||||||
|
|
||||||
|
stw rg2, bpr, 8 // store result
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
|
||||||
|
// lib:
|
||||||
|
// print.dsa
|
||||||
|
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print "<relative path>""
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print
|
||||||
|
//
|
||||||
|
// usage for reset:
|
||||||
|
// push pcx
|
||||||
|
// jmp print::reset
|
||||||
|
//
|
||||||
|
// usage for clear:
|
||||||
|
// push pcx
|
||||||
|
// jmp print::clear
|
||||||
|
//
|
||||||
|
// usage for print_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_byte
|
||||||
|
//
|
||||||
|
// usage for print_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_word
|
||||||
|
//
|
||||||
|
// usage for print_num:
|
||||||
|
// push (register containing number to print in decimal)
|
||||||
|
// push pcx
|
||||||
|
// jmp print::print_num
|
||||||
|
//
|
||||||
|
|
||||||
|
include maths "./maths.dsa"
|
||||||
|
|
||||||
|
dw display: 0x20000
|
||||||
|
dw current: 0x20000
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) to the screen. (no trailing whitespace unless explicitly provided)
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
_print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
addi rg1, 1
|
||||||
|
|
||||||
|
jmp _print_loop
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
println:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
_println_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _println_end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
addi rg1, 1
|
||||||
|
|
||||||
|
jmp _println_loop
|
||||||
|
|
||||||
|
_println_end:
|
||||||
|
call print_newline
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the screen.
|
||||||
|
print_word:
|
||||||
|
// initialise
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// load byte into acc
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
addi rg1, 3
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
subi rg1, 1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
|
||||||
|
addi rg1, 4
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the screen.
|
||||||
|
print_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the screen in hex.
|
||||||
|
print_hex_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
ldb bpr, rg0, 8
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 9
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 10
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 11
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the screen in hex.
|
||||||
|
print_hex_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
call _print_hex_byte
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// function body
|
||||||
|
_print_hex_byte:
|
||||||
|
// mask to get lower nibble
|
||||||
|
lli 0xF, rg2
|
||||||
|
// save rg0 state
|
||||||
|
push rg0
|
||||||
|
|
||||||
|
shr rg0, 4
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
pop rg0
|
||||||
|
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
return
|
||||||
|
|
||||||
|
// print a hex digit
|
||||||
|
_print_hex_nibble:
|
||||||
|
lli 10, rg3
|
||||||
|
cmp rg0, rg3
|
||||||
|
jlt _print_hex_nibble_number
|
||||||
|
addi rg0, 0x37, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
return
|
||||||
|
|
||||||
|
// helper function.
|
||||||
|
_print_hex_nibble_number:
|
||||||
|
addi rg0, 0x30, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
return
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// print whitespace
|
||||||
|
print_whitespace:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw current, rg1
|
||||||
|
lli 0x20, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// print newline
|
||||||
|
print_newline:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
// load variables into registers
|
||||||
|
ldw display, rg0
|
||||||
|
ldw current, rg1
|
||||||
|
|
||||||
|
// get the offset from the display base
|
||||||
|
sub rg1, rg0, rg0
|
||||||
|
|
||||||
|
lwi 80, rg2
|
||||||
|
pusha 3
|
||||||
|
push rg0
|
||||||
|
push rg2
|
||||||
|
call maths::divmod
|
||||||
|
pop zero // result
|
||||||
|
pop rg3 // remainder
|
||||||
|
popa 3
|
||||||
|
|
||||||
|
sub rg1, rg3, rg2
|
||||||
|
addi rg2, 80, rg1
|
||||||
|
|
||||||
|
// _end saves the display state
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints arg[0] as a decimal number to the screen.
|
||||||
|
print_num:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8 // load number to print
|
||||||
|
lli 0, rg5 // rg5 = digit counter
|
||||||
|
|
||||||
|
// check if number is zero
|
||||||
|
cmp rg0, zero
|
||||||
|
jne _print_num_extract_digits
|
||||||
|
|
||||||
|
// special case: print '0' for zero
|
||||||
|
lli 0x30, rg6
|
||||||
|
push rg6 // push digit to stack buffer
|
||||||
|
lli 1, rg5 // we have 1 digit
|
||||||
|
jmp _print_num_output
|
||||||
|
|
||||||
|
_print_num_extract_digits:
|
||||||
|
// divide by 10 repeatedly to get digits
|
||||||
|
cmp rg0, zero
|
||||||
|
jeq _print_num_output
|
||||||
|
|
||||||
|
// call divmod(rg0, 10)
|
||||||
|
push rg0 // dividend
|
||||||
|
lli 10, rg1
|
||||||
|
push rg1 // divisor (10)
|
||||||
|
call maths::divmod
|
||||||
|
pop rg0 // quotient (continue dividing this)
|
||||||
|
pop rg1 // remainder (the digit)
|
||||||
|
|
||||||
|
// convert digit to ASCII and push to stack buffer
|
||||||
|
addi rg1, 0x30, rg6 // convert to ASCII
|
||||||
|
push rg6 // push digit to stack
|
||||||
|
inc rg5 // increment digit counter
|
||||||
|
|
||||||
|
jmp _print_num_extract_digits
|
||||||
|
|
||||||
|
_print_num_output:
|
||||||
|
// now print digits (pop them off in reverse order)
|
||||||
|
ldw current, rg1 // get display pointer
|
||||||
|
|
||||||
|
_print_num_output_loop:
|
||||||
|
// check if we've printed all digits
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _print_num_done
|
||||||
|
|
||||||
|
// pop digit and print it
|
||||||
|
pop rg6
|
||||||
|
stb rg6, rg1
|
||||||
|
addi rg1, 1
|
||||||
|
dec rg5
|
||||||
|
|
||||||
|
jmp _print_num_output_loop
|
||||||
|
|
||||||
|
_print_num_done:
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// resets the cursor position on the screen to 0x20000. (0,0)
|
||||||
|
reset:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
ldw display, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// clears the screen
|
||||||
|
clear:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
// display size = 2000 bytes / 500 words
|
||||||
|
lli 500 rg0
|
||||||
|
ldw display, rg1
|
||||||
|
|
||||||
|
_clear_loop:
|
||||||
|
dec rg0
|
||||||
|
stw zero, rg1
|
||||||
|
addi rg1, 4
|
||||||
|
cmp rg0, zero
|
||||||
|
jgt _clear_loop
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// return
|
||||||
|
_end:
|
||||||
|
stw rg1, current
|
||||||
|
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
// lib:
|
||||||
|
// print_serial.dsa
|
||||||
|
|
||||||
|
// usage:
|
||||||
|
//
|
||||||
|
// include print_serial "<relative path>"
|
||||||
|
//
|
||||||
|
// usage for print:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print
|
||||||
|
//
|
||||||
|
// usage for print_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_byte
|
||||||
|
//
|
||||||
|
// usage for print_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_word
|
||||||
|
//
|
||||||
|
// usage for print_hex_byte:
|
||||||
|
// push (register containing byte)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_hex_byte
|
||||||
|
//
|
||||||
|
// usage for print_hex_word:
|
||||||
|
// push (register containing word)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_hex_word
|
||||||
|
//
|
||||||
|
// usage for print_num:
|
||||||
|
// push (register containing number to print in decimal)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::print_num
|
||||||
|
//
|
||||||
|
// usage for println:
|
||||||
|
// push (register containing address of string)
|
||||||
|
// push pcx
|
||||||
|
// jmp print_serial::println
|
||||||
|
//
|
||||||
|
|
||||||
|
include maths "./maths.dsa"
|
||||||
|
|
||||||
|
dw serial: 0x207D0 // 0x20000 + 2000
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) to the serial port.
|
||||||
|
print:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_print_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
jmp _print_loop
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the string at addr(arg[0]) followed by a newline to the serial port.
|
||||||
|
println:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_println_loop:
|
||||||
|
ldb rg0, acc
|
||||||
|
cmp acc, zero
|
||||||
|
jeq _println_end
|
||||||
|
stb acc, rg1
|
||||||
|
|
||||||
|
addi rg0, 1
|
||||||
|
jmp _println_loop
|
||||||
|
|
||||||
|
_println_end:
|
||||||
|
lli 0x0A, rg2 // newline character
|
||||||
|
stb rg2, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the word in arg[0] as 4 raw bytes to the serial port.
|
||||||
|
print_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
shr rg0, 8
|
||||||
|
stb rg0, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the serial port.
|
||||||
|
print_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
stb rg0, rg1
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the value of arg[0] to the serial port in hex.
|
||||||
|
print_hex_word:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
ldb bpr, rg0, 8
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 9
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 10
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
ldb bpr, rg0, 11
|
||||||
|
push rg0
|
||||||
|
call _print_hex_byte
|
||||||
|
addi spr, 4
|
||||||
|
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints the last byte of arg[0] to the serial port in hex.
|
||||||
|
print_hex_byte:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
call _print_hex_byte
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// function body
|
||||||
|
_print_hex_byte:
|
||||||
|
lli 0xF, rg2
|
||||||
|
push rg0
|
||||||
|
|
||||||
|
shr rg0, 4
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
pop rg0
|
||||||
|
|
||||||
|
and rg0, rg2, rg0
|
||||||
|
call _print_hex_nibble
|
||||||
|
return
|
||||||
|
|
||||||
|
// print a hex digit
|
||||||
|
_print_hex_nibble:
|
||||||
|
lli 10, rg3
|
||||||
|
cmp rg0, rg3
|
||||||
|
jlt _print_hex_nibble_number
|
||||||
|
addi rg0, 0x37, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
return
|
||||||
|
|
||||||
|
_print_hex_nibble_number:
|
||||||
|
addi rg0, 0x30, rg0
|
||||||
|
stb rg0, rg1
|
||||||
|
return
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// prints arg[0] as a decimal number to the serial port.
|
||||||
|
print_num:
|
||||||
|
push bpr
|
||||||
|
mov spr, bpr
|
||||||
|
|
||||||
|
ldw bpr, rg0, 8
|
||||||
|
lli 0, rg5
|
||||||
|
|
||||||
|
cmp rg0, zero
|
||||||
|
jne _print_num_extract_digits
|
||||||
|
|
||||||
|
lli 0x30, rg6
|
||||||
|
push rg6
|
||||||
|
lli 1, rg5
|
||||||
|
jmp _print_num_output
|
||||||
|
|
||||||
|
_print_num_extract_digits:
|
||||||
|
cmp rg0, zero
|
||||||
|
jeq _print_num_output
|
||||||
|
|
||||||
|
push rg0
|
||||||
|
lli 10, rg1
|
||||||
|
push rg1
|
||||||
|
call maths::divmod
|
||||||
|
pop rg0
|
||||||
|
pop rg1
|
||||||
|
|
||||||
|
addi rg1, 0x30, rg6
|
||||||
|
push rg6
|
||||||
|
inc rg5
|
||||||
|
|
||||||
|
jmp _print_num_extract_digits
|
||||||
|
|
||||||
|
_print_num_output:
|
||||||
|
lwi 0x207D0, rg1
|
||||||
|
|
||||||
|
_print_num_output_loop:
|
||||||
|
cmp rg5, zero
|
||||||
|
jeq _print_num_done
|
||||||
|
|
||||||
|
pop rg6
|
||||||
|
stb rg6, rg1
|
||||||
|
dec rg5
|
||||||
|
|
||||||
|
jmp _print_num_output_loop
|
||||||
|
|
||||||
|
_print_num_done:
|
||||||
|
jmp _end
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// return
|
||||||
|
_end:
|
||||||
|
mov bpr, spr
|
||||||
|
pop bpr
|
||||||
|
return
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
include print: "./lib/print.dsa";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
print::print("Hello, World!");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user