started on lazy simple TUI

This commit is contained in:
Steven Hugg 2014-01-16 13:05:14 -05:00
parent 92ba23e8b3
commit cae5e36d74
4 changed files with 260 additions and 8 deletions

View File

@ -4,5 +4,8 @@ RUSTC=rustc
test:
$(RUSTC) -Z debug-info -o appletest --test apple.rs
./appletest
tui:
$(RUSTC) -Z debug-info tui.rs

16
a2.rs
View File

@ -2,14 +2,14 @@
use mem::Mem;
use util::Xorshift;
static GR_TXMODE: int = 1;
static GR_MIXMODE: int = 2;
static GR_PAGE1: int = 4;
static GR_HIRES: int = 8;
pub static GR_TXMODE: u8 = 1;
pub static GR_MIXMODE: u8 = 2;
pub static GR_PAGE1: u8 = 4;
pub static GR_HIRES: u8 = 8;
static HW_LO: u16 = 0xC000;
static ROM_LO: u16 = 0xD000;
static ROM_LEN: u16 = 0x3000;
pub static HW_LO: u16 = 0xC000;
pub static ROM_LO: u16 = 0xD000;
pub static ROM_LEN: u16 = 0x3000;
pub trait Peripheral
{
@ -58,7 +58,7 @@ pub struct AppleII
debugflags: int,
kbdlatch: u8,
grswitch: u16,
grswitch: u8,
soundstate: bool,
aux: LangCardState,
nreads: u16 // counts # of reads for noise() fn

145
lazyterm.rs Normal file
View File

@ -0,0 +1,145 @@
use std::vec;
use std::io;
use std::io::stdio::{StdReader,StdWriter};
use std::io::Timer;
// TODO: use these but they are inconvenient
pub struct TermColor(u8);
#[deriving(Clone)]
pub struct TermCell
{
bg: u8,
fg: u8,
ch: char
}
//static BLACK: TermColor = TermColor(0);
//static WHITE: TermColor = TermColor(15);
pub static BLACK: u8 = 0;
pub static WHITE: u8 = 15;
pub static EMPTY: TermCell = TermCell { fg:WHITE, bg:BLACK, ch:' ' };
#[deriving(Clone)]
pub struct Buffer
{
buf: ~[~[TermCell]],
width: uint,
height: uint,
}
impl Buffer
{
pub fn new(cols: uint, rows: uint) -> Buffer
{
Buffer { width:cols, height:rows, buf:vec::from_elem(rows, vec::from_elem(cols, EMPTY)) }
}
pub fn set(&mut self, col: uint, row: uint, cell: TermCell)
{
self.buf[row][col] = cell;
}
}
pub struct Terminal
{
hin : StdReader,
hout: StdWriter,
lastbuf: Buffer,
}
impl Terminal
{
pub fn new() -> Terminal
{
Terminal { lastbuf: Buffer::new(0,0), hin: io::stdin(), hout: io::stdout() }
}
fn reset(&mut self)
{
self.hout.write_str(format!("\x1b[0"));
}
fn update(&mut self, buf: &Buffer)
{
let ref mut hout = self.hout;
let mut prev = EMPTY;
for y in range(0,buf.height)
{
for x in range(0,buf.width)
{
let cell = buf.buf[y][x];
let last = self.lastbuf.buf[y][x];
let mut dirty = false;
if (cell.fg != prev.fg)
{
hout.write_str(format!("\x1b[38;5;{}m", cell.fg));
dirty = true;
}
if (cell.bg != prev.bg)
{
hout.write_str(format!("\x1b[48;5;{}m", cell.bg));
dirty = true;
}
// TODO
//if (dirty || cell.ch != last.ch)
{
hout.write_char(cell.ch);
}
prev = cell;
}
hout.write_char('\n');
}
}
fn redraw(&mut self, buf: &Buffer)
{
let ref mut hout = self.hout;
for y in range(0,buf.height)
{
for x in range(0,buf.width)
{
let cell = buf.buf[y][x];
hout.write_str(format!("\x1b[38;5;{}m", cell.fg));
hout.write_str(format!("\x1b[48;5;{}m", cell.bg));
hout.write_char(cell.ch);
}
hout.write_char('\n');
}
}
pub fn refresh(&mut self, buf: &Buffer)
{
self.reset();
if buf.width == self.lastbuf.width && buf.height == self.lastbuf.height
{
// scroll up N lines
self.hout.write_str(format!("\x1b[{}A", buf.height));
// update dirty cells
self.update(buf);
} else {
// redraw entire window
// TODO: rescroll window
self.redraw(buf);
}
self.reset();
self.lastbuf = buf.clone();
}
}
//
fn main()
{
let mut buf = Buffer::new(40,24);
let mut term = Terminal::new();
let mut timer = Timer::new().unwrap();
for i in range(0u8,15)
{
buf.set(1, 1, TermCell { bg:i, fg:i+1, ch:'#' } );
term.refresh(&buf);
timer.sleep(50);
}
}

104
tui.rs Normal file
View File

@ -0,0 +1,104 @@
#[feature(link_args, macro_rules)];
use cpu::Cpu;
use mem::Mem;
use a2::AppleII;
use a2::Peripheral;
use diskii::DiskController;
use util::current_time_millis;
use lazyterm::{Terminal,Buffer};
// NB: This must be first to pick up the macro definitions. What a botch.
#[macro_escape]
pub mod util;
#[macro_escape]
pub mod cpu;
pub mod mem;
pub mod a2;
pub mod diskii;
pub mod lazyterm;
static text_lut: [u16, ..8*3] = [
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380,
0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8,
0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0
];
static flashInterval: u64 = 500;
fn draw_text_line(a2: &AppleII, buf: &mut Buffer, flash: bool, y: uint)
{
// get the base address of this line
let base = text_lut[y] + if (a2.grswitch & a2::GR_PAGE1) != 0 { 0x800 } else { 0x400 };
for x in range(0u,40)
{
let mut b = a2.mem[base + x as u16];
let invert: bool;
// invert flash characters 1/2 of the time
if (b >= 0x80)
{
invert = false;
}
else if (b >= 0x40)
{
invert = flash;
if (flash) { b -= 0x40; } else { b += 0x40; }
}
else
{
invert = true;
}
// if the char. changed, draw it
let ch = (b & 0x7f) as char;
let cell = lazyterm::TermCell { fg:lazyterm::WHITE, bg:lazyterm::BLACK, ch:ch };
buf.set(x, y, cell);
//drawTextChar(x, y, b & 0x7f, invert);
}
}
fn update_term_buf(a2: &AppleII, buf: &mut Buffer, flash: bool)
{
for y in range(0u,24)
{
draw_text_line(a2, buf, flash, y);
}
}
fn main()
{
let mut a2 = AppleII::new();
a2.read_roms();
let mut dc: DiskController = DiskController::new();
dc.load_disk(0, "JUNK4.DSK");
assert!(dc.has_disk(0));
a2.set_slot(6, ~dc);
let mut cpu = Cpu::new(a2);
cpu.reset();
let mut term = Terminal::new();
let mut buf = Buffer::new(40,24);
// mismatched types: expected `<generic integer #5>` but found `<generic float #0>`
let speedup = 2;
let clocks_per_msec = (1000 * speedup);
let mut t0 = current_time_millis();
loop
{
// cursor flashing?
let flash = (t0 % (flashInterval<<1)) > flashInterval;
update_term_buf(&cpu.mem, &mut buf, flash);
term.refresh(&buf);
let t1 = current_time_millis();
let cycle = cpu.cy + (t1-t0)*clocks_per_msec;
while cpu.cy < cycle
{
cpu.step();
}
t0 = t1;
}
}