|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.8 root 7: //
8: // Pluto-X (独自の仮想ボード)
9: //
10:
1.1 root 11: #include "pluto.h"
1.1.1.2 root 12: #include "mainapp.h"
1.1.1.9 ! root 13: #include "mainbus.h"
! 14: #include "mainram.h"
1.1.1.3 root 15: #include "mpu680x0.h"
1.1.1.9 ! root 16: #include "sram.h"
1.1.1.5 root 17:
1.1.1.8 root 18: // コンストラクタ
1.1 root 19: PlutoDevice::PlutoDevice()
1.1.1.9 ! root 20: : inherited(OBJ_PLUTO)
1.1 root 21: {
22: }
23:
1.1.1.8 root 24: // デストラクタ
1.1 root 25: PlutoDevice::~PlutoDevice()
26: {
27: }
28:
1.1.1.8 root 29: // リセット
1.1.1.4 root 30: void
1.1.1.8 root 31: PlutoDevice::ResetHard(bool poweron)
1.1.1.4 root 32: {
33: // XXX not yet
34: m_count = 0;
35: }
36:
1.1.1.3 root 37: // ROM
38: /*static*/ const uint16
39: PlutoDevice::rom[] = {
40: // ホストファイル起動
41: 0x00ea, 0xc004, // .dc.l _start ; 起動アドレス
42: //_start:
1.1.1.9 ! root 43: 0x46fc, 0x2700, // move.w #0x2700,%sr
1.1.1.3 root 44: 0x2039, 0x00ea, 0xc450, // move.l (ROMIO_LOAD),%d0
1.1.1.9 ! root 45: 0x6b04, // bmi.s _err
! 46: 0x2040, // move.l %d0,%a0
! 47: 0x4e90, // jsr (%a0)
1.1.1.3 root 48: //_err:
49: 0x43fa, 0x000c, // lea.l (_errmsg),%a1
50: 0x7021, 0x4e4f, // IOCS B_PRINT
51: //_loop:
52: 0x4e72, 0x2600, // stop #0x2600
53: 0x60fa, // bra.s _loop
54: //_errmsg:
55: 0x2a2a, 0x2043, 0x616e, // .dc.b "** Can"
56: 0x6e6f, 0x7420, 0x6c6f, // .dc.b "not lo"
57: 0x6164, 0x2068, 0x6f73, // .dc.b "ad hos"
58: 0x7420, 0x6669, 0x6c65, // .dc.b "t file"
59: 0x2e00, // .dc.b ".",0
60: };
61:
62: uint64
63: PlutoDevice::Read8(uint32 addr)
64: {
1.1.1.9 ! root 65: uint32 offset = addr - baseaddr;
1.1.1.3 root 66: uint32 data;
67:
68: if (offset < sizeof(rom)) {
69: data = rom[offset / 2];
70: if ((offset & 1) == 0) {
71: return data >> 8;
72: } else {
73: return data & 0xff;
74: }
75: }
76:
77: return (uint64)-1;
78: }
79:
80: uint64
81: PlutoDevice::Read16(uint32 addr)
82: {
1.1.1.9 ! root 83: uint32 offset = addr - baseaddr;
1.1.1.3 root 84:
85: if (offset < sizeof(rom)) {
86: return rom[offset / 2];
87: }
88:
89: return (uint64)-1;
90: }
91:
92: uint64
93: PlutoDevice::Read32(uint32 addr)
94: {
1.1.1.9 ! root 95: uint32 offset = addr - baseaddr;
1.1.1.3 root 96: uint32 data;
97:
98: if (offset < sizeof(rom)) {
99: data = rom[offset / 2] << 16;
100: data |= rom[(offset / 2) + 1];
101: return data;
102: }
103: switch (offset) {
104: case 0x450: // ROMIO_LOAD
105: return ROM_Load();
106:
107: default:
108: break;
109: }
110: return (uint64)-1;
111: }
112:
113: uint64
114: PlutoDevice::Write8(uint32 addr, uint32 data)
115: {
116: switch (addr) {
117: case 0xeac403:
118: write_8_benchmark(addr, data);
119: break;
120: default:
121: break;
122: }
123: putlog(0, "未実装バイト書き込み $%06x", addr);
124: return 0;
125: }
126:
127: uint64
128: PlutoDevice::Write16(uint32 addr, uint32 data)
129: {
130: putlog(0, "未実装ワード書き込み $%06x", addr);
131: return 0;
132: }
133:
134: uint64
135: PlutoDevice::Peek8(uint32 addr)
136: {
1.1.1.9 ! root 137: uint32 offset = addr - baseaddr;
1.1.1.3 root 138: uint32 data;
139:
140: if (offset < sizeof(rom)) {
141: data = rom[offset / 2];
142: if ((offset & 1) == 0) {
143: return data >> 8;
144: } else {
145: return data & 0xff;
146: }
147: }
148:
149: return (uint64)-1;
150: }
151:
152: //
153: // ホストファイル起動
154: //
155:
1.1.1.7 root 156: // -X オプションで指定されたホストファイルをロードする。
1.1.1.3 root 157: // ロードできればエントリポイントを返す。
1.1.1.7 root 158: // exec_file が指定されている時に呼ぶこと。
1.1.1.3 root 159: uint32
160: PlutoDevice::ROM_Load()
161: {
1.1.1.7 root 162: assert(gMainApp.exec_file);
1.1.1.3 root 163:
1.1.1.9 ! root 164: auto mainbus = GetMainbusDevice();
! 165: auto mainram = GetMainRAMDevice();
! 166: auto mpu680x0 = GetMPU680x0Device();
! 167: auto sram = GetSRAMDevice();
! 168:
1.1.1.3 root 169: // ホストファイルをロード
1.1.1.9 ! root 170: LoadInfo info(gMainApp.exec_file);
! 171: if (mainram->LoadFromFile(&info) == false) {
! 172: return -1;
! 173: }
! 174:
! 175: // NetBSD/x68k のプライマリブートローダが /boot を読み込む時、および
! 176: // /boot がカーネルを読み込む時には、レジスタ渡しのパラメータがあるので、
! 177: // ここで用意する。
! 178: // 本当はターゲットが NetBSD/x68k の /boot とカーネルの時に限定すべきの
! 179: // ような気もするけど、とりあえず。必要なパラメータは
! 180: //
! 181: // %d6 に bootdev、NetBSD/x68k の場合は
! 182: // bootdev = $MACULPTT
! 183: // ||||||++- major type
! 184: // |||||+--- パーティション番号
! 185: // ||||+---- SCSI なら LUN、それ以外なら 0
! 186: // |||+----- unit (SCSI なら SCSI ID、FD ならドライブ番号)
! 187: // ||+------ ctlr (spc0 なら 0 のやつ)
! 188: // |+------- adaptor (spc = 1、mha = 2)
! 189: // +-------- magic ($a)
! 190: // major type は fd=2、MemoryDisk=8、sd=4、(st=5、)、cd=7、ne=255。
! 191: //
! 192: // %d7 に howto だが今の所使ってないようだ。
! 193: //
! 194: // 一方、/boot がカーネルを読み込む時はこれに加えてスタック渡しの
! 195: // パラメータもある。これは (取り出す順に)
! 196: // firstpa.L .. 読み込んだカーネル先頭の物理アドレス?
! 197: // physsize.L .. RAM 容量 (SRAM の $ed0008.L の値)
! 198: // esym.L .. シンボルの後ろ、なので実質読み込んだ全体のサイズ
! 199: //
! 200: // これも本当はターゲットが NetBSD/x68k のカーネルの時に限定すべきの
! 201: // ような気もするけど、とりあえず。
! 202:
! 203: mpu680x0->reg.D[6] = 0xa1000004;
! 204: mpu680x0->reg.D[7] = 0;
! 205:
! 206: mpu680x0->reg.A[7] = sram->GetRAMSize();
! 207: mpu680x0->reg.A[7] -= 4;
! 208: mainbus->Write32(mpu680x0->reg.A[7], info.end - info.start); // esym
1.1.1.3 root 209:
1.1.1.9 ! root 210: mpu680x0->reg.A[7] -= 4;
! 211: mainbus->Write32(mpu680x0->reg.A[7], sram->GetRAMSize()); // physsize
! 212:
! 213: mpu680x0->reg.A[7] -= 4;
! 214: mainbus->Write32(mpu680x0->reg.A[7], 0x00000000); // firstpa
1.1.1.3 root 215:
1.1.1.9 ! root 216: return info.entry;
1.1.1.3 root 217: }
218:
1.1 root 219: // ベンチマーク開始
220: void
221: PlutoDevice::benchmark_start(uint32 data)
222: {
223: m_test_num = data;
224:
225: // テスト番号によってパラメータをセット
226: // #2,#3 は NOP による実行サイクル測定。
227: // #4,#5 は movem によるデータ空間アクセス測定。
228: switch (m_test_num) {
229: case 2:
230: case 3:
231: m_test_name = "NOP";
232: m_inst_len = 2;
233: m_inst_cycle = 2;
234: break;
235: case 4:
236: case 5:
237: m_test_name = "MOVEM";
238: m_inst_len = 8;
239: m_inst_cycle = 244; // XXX 見直すこと
240: break;
241: }
242:
243: // 測定開始時だけ表示
244: if (m_count == 0) {
245: putlog(0, "ベンチマーク開始");
246:
247: // 命令開始アドレス。この時点で REG_PC は次をさしている
1.1.1.9 ! root 248: m_start_addr = mpu->GetPPC();
1.1 root 249: }
250:
251: // 測定開始
252: gettimeofday(&m_start, NULL);
253: }
254:
255: // ベンチマーク終了
256: void
257: PlutoDevice::benchmark_end()
258: {
259: const int SECONDS = 5; // 測定秒数 [sec]
260: timeval end, result;
261: int t;
262: int num_of_inst; // 1ループ中の命令セット数
263: double speed;
264:
265: // 測定終了
266: gettimeofday(&end, NULL);
267: m_count++;
268:
269: // 今回1セット分の実行時間 [usec]
270: timersub(&end, &m_start, &result);
271:
272: // 総実行時間
273: timeradd(&result, &m_total, &m_total);
274:
275: // 規定秒数に満たなければ、もう1セット繰り返し。
276: // 次が jmp 命令なのでこの命令を抜けるだけでいい。
277: if (m_total.tv_sec < SECONDS) {
278: return;
279: }
280:
281: // 規定秒数に達していれば、測定終了
282: t = m_total.tv_sec * 1000*1000 + m_total.tv_usec;
283: putlog(0, "ベンチマーク#%d 終了 (%d 回, 計 %d.%03d msec)",
1.1.1.2 root 284: gMainApp.benchmark_mode, m_count, t / 1000, t % 1000);
1.1 root 285:
286: // 1ループ中の命令セット数を算出。REG_PPC はこの命令の開始番地
1.1.1.9 ! root 287: num_of_inst = (mpu->GetPPC() - m_start_addr) / m_inst_len;
1.1 root 288:
289: // 68030 のクロック数 [MHz] に換算
290: speed = (double)(m_count * num_of_inst) * m_inst_cycle / t;
291:
292: // 表示用にベンチマーク ROM のリビジョンを取得
293: int rev;
294: rev = 0;
295: #if 0
296: IPLROM1 *iplrom1 = (IPLROM1 *)vm->SearchDevice(DEVICE_IPLROM1);
297: ASSERT(iplrom1);
298: if (!iplrom1->GetBenchmarkROM(m_test_num, NULL, &rev)) {
299: rev = 0;
300: }
301: #endif
302:
303: // XXX NetBSD ホストでは有効桁2桁と思われる
304: putlog(0, "ベンチマーク#%d.%d (%s 実行速度) 68030/%3.0fMHz, %d MIPS",
305: m_test_num, rev, m_test_name, speed, (m_count * num_of_inst) / t);
306:
307: // 電源オフ
308: // XXX とりあえずね
309: exit(1);
310: }
311:
312: //
313: void
314: PlutoDevice::write_8_benchmark(uint32 addr, uint32 data)
315: {
316: switch (data) {
317: case 0: // ベンチマーク終了
318: benchmark_end();
319: break;
320: case 2: // ベンチマーク開始
321: case 3:
322: case 4:
323: case 5:
324: benchmark_start(data);
325: break;
326: default:
1.1.1.8 root 327: VMPANIC("not impl");
1.1 root 328: }
329: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.