summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 615f3bfa05f19649cd57934b9885b2d8accdb7f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) 2025 taitep
// SPDX-License-Identifier: MIT
//
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
// See LICENSE file in the project root for full license text.

use std::{env, sync::Arc, time::Duration};

use trve::{
    consts::{Byte, DWord, HWord, Word},
    core::Core,
    exceptions::ExceptionType,
    mem::{DeviceEntry, MemConfig, MemDeviceInterface, PageNum, Ram},
};

use anyhow::{Result, bail};

use crate::basic_uart::BasicUart;

mod execload;

fn main() -> Result<()> {
    let mut ram = Ram::try_new(16 * 1024 * 1024 / 4096)?;
    let buf = ram.buf_mut();

    let args: Vec<String> = env::args().collect();

    if args.len() != 2 {
        eprintln!("USAGE: trve <ram_image>");
        bail!("Wrong number of arguments");
    }

    let entry_point = execload::load(&args[1], buf, 0x8000_0000)?;

    let uart = BasicUart::new();
    let uart = uart.spawn_poller(Duration::from_millis(10));

    let mem_cfg = MemConfig {
        ram: Arc::new(ram),
        ram_start: 0x8000_0000 / 4096,
        devices: Box::new([
            DeviceEntry {
                base: 0,
                size: 1,
                interface: Arc::new(DbgOut),
            },
            DeviceEntry {
                base: 1,
                size: 1,
                interface: uart,
            },
        ]),
    };

    let mut core = Core::new(mem_cfg);
    core.reset(entry_point);
    core.run();

    Ok(())
}

mod basic_uart;

struct DbgOut;

impl MemDeviceInterface for DbgOut {
    fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), ExceptionType> {
        eprintln!(
            "Wrote DWord {value:016x} to Debug-Out page {page}, offset {offset} (byte {})",
            offset * 8
        );
        Ok(())
    }

    fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
        eprintln!(
            "Wrote Word {value:08x} to Debug-Out page {page}, offset {offset} (byte {})",
            offset * 4
        );
        Ok(())
    }

    fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType> {
        eprintln!(
            "Wrote HWord {value:04x} to Debug-Out page {page}, offset {offset} (byte {})",
            offset * 2
        );
        Ok(())
    }

    fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
        eprintln!("Wrote Byte {value:02x} to Debug-Out page {page}, offset {offset}");
        Ok(())
    }

    fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> {
        Err(ExceptionType::LoadAccessFault)
    }

    fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
        Err(ExceptionType::LoadAccessFault)
    }

    fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
        Err(ExceptionType::LoadAccessFault)
    }

    fn read_byte(&self, _page: PageNum, _offset: u16) -> Result<Byte, ExceptionType> {
        Err(ExceptionType::LoadAccessFault)
    }

    fn get_atomic_word(
        &self,
        _page: PageNum,
        _offset: u16,
    ) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
        Err(ExceptionType::StoreAmoAccessFault)
    }

    fn get_atomic_dword(
        &self,
        _page: PageNum,
        _offset: u16,
    ) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
        Err(ExceptionType::StoreAmoAccessFault)
    }
}