tree checksum vpatch file split hunks

all signers: asciilifeform

antecedents:

press order:

m_genesis.kvasciilifeform

patch:

-
+ 27A062D2599973684B8FD9888BE347D9B492FC94B9B29AD776DD672B11FB49606D226CEABBE5295F72A56FEC277AEB465A9072961134BE60E8054FBD8A705B6D
m/MANIFEST.TXT
(0 . 0)(1 . 2)
5 586606 m_genesis "Genesis."
6
-
+ 7A4692E9946054A9CB6B2668D3DF0D10D982DF49FA6114D08E2D3D78A7C23FE09C90DD5D8041A43E2F697A4324D1BEDEEB4B3AA51D267864506B97D22D8D546E
m/Makefile
(0 . 0)(1 . 37)
11 PROJ = m
12 ASMER = yasm
13 ASMARGS = -f elf64 -g null
14 DWARFARGS = -f elf64 -g dwarf2
15 LINKER = ld
16 LNKARGS = --strip-all
17 BUILD=build
18 BIN=bin
19
20 all: asm lnk
21
22 asm:
23 $(ASMER) $(ASMARGS) $(PROJ).asm -o $(BUILD)/$(PROJ).o
24
25 dwarf:
26 $(ASMER) $(DWARFARGS) $(PROJ).asm -o $(BUILD)/$(PROJ).o
27
28 lnk:
29 $(LINKER) $(LNKARGS) $(BUILD)/$(PROJ).o -o $(BIN)/$(PROJ)
30
31 dbglnk:
32 $(LINKER) $(LNKARGS) $(BUILD)/$(PROJ).o -o $(BIN)/$(PROJ)
33
34 dis: dwarf lnk
35 objdump --disassembler-options=intel -D $(BIN)/$(PROJ)
36
37 dissrc: dwarf dbglnk
38 objdump --disassembler-options=intel -S -D $(BIN)/$(PROJ)
39
40 disraw: all
41 objdump --disassembler-options=intel -D $(BIN)/$(PROJ)
42
43 debug: clean dwarf dbglnk
44 gdb --command misc/m.gdb
45
46 clean:
47 rm -f $(BUILD)/*.o $(BIN)/$(PROJ)
-
+ 5FDBAE897EB301A711BF95707F329517DB540E34C182A5BEEC96E93D5D0D856CEC2ED6B01C1191F865E8D1C45709A462C70C3005D4AA3676EB445D1479EDF2E5
m/bin/README
(0 . 0)(1 . 1)
52 Placeholder.
-
+ 5FDBAE897EB301A711BF95707F329517DB540E34C182A5BEEC96E93D5D0D856CEC2ED6B01C1191F865E8D1C45709A462C70C3005D4AA3676EB445D1479EDF2E5
m/build/README
(0 . 0)(1 . 1)
57 Placeholder.
-
+ B94991DF360AAA3C332DBEF2217079DBF8F67D37CB2E09BD4F3B5C093E789B90E8FCC33831D32204184D79EC320A74BB55F64A2215DDE60BB61DD5716983A6D6
m/bus.asm
(0 . 0)(1 . 173)
62 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
63 ;; ;;
64 ;; This file is part of 'M', a MIPS system emulator. ;;
65 ;; ;;
66 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
67 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
68 ;; ;;
69 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
70 ;; distribute this software ; Should you use this software for any purpose, ;;
71 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
72 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
73 ;; continue doing so for the indefinite future. In any case, please ;;
74 ;; always : read and understand any software ; verify any PGP signatures ;;
75 ;; that you use - for any purpose. ;;
76 ;; ;;
77 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
78 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
79
80 ;; Universal MMIO Bus Dispatcher. Addition of new simulated devices will NOT
81 ;; require any changes to this mechanism. Be sure to add any device component
82 ;; to 'devices.asm'.
83 ;; NOTE 1: The DECLARE_BUS_DEVICE macro is valid ONLY inside text included by
84 ;; 'devices.asm' !
85 ;; NOTE 2: Currently there is NO support for devices which demand a
86 ;; non-contiguous MMIO segment !
87 ;; NOTE 3: Make ABSOLUTELY certain that the MMIO Device ranges do not overlap!
88
89 section .text
90
91 ;-----------------------------------------------------------------------------
92 ; MMIO_ADDR
93 ;-----------------------------------------------------------------------------
94 %define MMIO_ADDR(A) (MMIO_BASE + A) ; Address to be offset from MMIO_BASE
95 ;-----------------------------------------------------------------------------
96
97 ;-----------------------------------------------------------------------------
98 ; Proclaim Device and connect it to Bus; %1: Name, %2: Base Addr, %3: Top Addr
99 ;-----------------------------------------------------------------------------
100 %macro DECLARE_BUS_DEVICE 3
101
102 %define %1_BASE MMIO_ADDR(%2) ;; Declare DEVICE_BASE MMIO Address (first)
103 %define %1_TOP MMIO_ADDR(%3) ;; Declare DEVICE_TOP MMIO Address (last)
104
105 ;; Put this device's MMIO range in _Phys_Device_Read_Word's set of cases
106 SECTION .PD_Rd_Word
107 JMP_If_In eax, %1_BASE, %1_TOP, _PD_Read_Word_%1
108
109 ;; Put this device's MMIO range in _Phys_Device_Write_Word's set of cases
110 SECTION .PD_Wr_Word
111 JMP_If_In eax, %1_BASE, %1_TOP, _PD_Write_Word_%1
112
113 ;; Put this device's MMIO range in _Phys_Device_Read_Byte's set of cases
114 SECTION .PD_Rd_Byte
115 JMP_If_In eax, %1_BASE, %1_TOP, _PD_Read_Byte_%1
116
117 ;; Put this device's MMIO range in _Phys_Device_Write_Byte's set of cases
118 SECTION .PD_Wr_Byte
119 JMP_If_In eax, %1_BASE, %1_TOP, _PD_Write_Byte_%1
120
121 ;; Put this device's initialization routine in the list of
122 ;; called by _Phys_Devices_Initialize:
123 SECTION .PD_Initialize
124 call _Device_Init_%1
125
126 ;; Put this device's termination routine in the list of
127 ;; called by _Phys_Devices_Shutdown:
128 SECTION .PD_Shutdown
129 call _Device_Shutdown_%1
130
131 section .text ;; Resume the .text section.
132
133 %endmacro
134 ;-----------------------------------------------------------------------------
135
136 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
137 ;; Prologues of Physical Device Bus Wires ;;
138 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
139
140 ;-----------------------------------------------------------------------------
141 ; Device Read Word -- we jump here from _Virt_Read_Word if pAddr in range
142 ;-----------------------------------------------------------------------------
143 section .PD_Rd_Word progbits exec alloc nowrite
144 _Phys_Device_Read_Word:
145 ;-----------------------------------------------------------------------------
146
147 ;-----------------------------------------------------------------------------
148 ; Device Write Word -- we jump here from _Virt_Write_Word if pAddr in range
149 ;-----------------------------------------------------------------------------
150 section .PD_Wr_Word progbits exec alloc nowrite
151 _Phys_Device_Write_Word:
152 ;-----------------------------------------------------------------------------
153
154 ;-----------------------------------------------------------------------------
155 ; Device Read Byte -- we jump here from _Virt_Read_Byte if pAddr in range
156 ;-----------------------------------------------------------------------------
157 section .PD_Rd_Byte progbits exec alloc nowrite
158 _Phys_Device_Read_Byte:
159 ;-----------------------------------------------------------------------------
160
161 ;-----------------------------------------------------------------------------
162 ; Device Write Byte -- we jump here from _Virt_Write_Byte if pAddr in range
163 ;-----------------------------------------------------------------------------
164 section .PD_Wr_Byte progbits exec alloc nowrite
165 _Phys_Device_Write_Byte:
166 ;-----------------------------------------------------------------------------
167
168 ;-----------------------------------------------------------------------------
169 ; Device Initialization
170 ;-----------------------------------------------------------------------------
171 section .PD_Initialize progbits exec alloc nowrite
172 _Phys_Devices_Initialize:
173 ;-----------------------------------------------------------------------------
174
175 ;-----------------------------------------------------------------------------
176 ; Device Shutdown
177 ;-----------------------------------------------------------------------------
178 section .PD_Shutdown progbits exec alloc nowrite
179 _Phys_Devices_Shutdown:
180 ;-----------------------------------------------------------------------------
181
182 ;; ALL Device implementations MUST be included from:
183 %include "devices/devices.asm"
184
185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
186 ;; Epilogues of Physical Device Bus Wires ;;
187 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
188
189 ;-----------------------------------------------------------------------------
190 SECTION .PD_Rd_Word
191 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
192 ;; Unknown Device ?
193 xor eax, eax ; Always return 0
194 ACHTUNG "Read Word from Unknown Device?" ; TODO: print detail
195 ret
196 ;-----------------------------------------------------------------------------
197
198 ;-----------------------------------------------------------------------------
199 SECTION .PD_Wr_Word
200 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201 ;; Unknown Device ?
202 ACHTUNG "Write Word to Unknown Device?" ; TODO: print detail
203 ret
204 ;-----------------------------------------------------------------------------
205
206 ;-----------------------------------------------------------------------------
207 SECTION .PD_Rd_Byte
208 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
209 ;; Unknown Device ?
210 xor eax, eax ; Always return 0
211 ACHTUNG "Read Byte from Unknown Device?" ; TODO: print detail
212 ret
213 ;-----------------------------------------------------------------------------
214
215 ;-----------------------------------------------------------------------------
216 SECTION .PD_Wr_Byte
217 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
218 ;; Unknown Device ?
219 ACHTUNG "Write Byte to Unknown Device?" ; TODO: print detail
220 ret
221 ;-----------------------------------------------------------------------------
222
223 ;-----------------------------------------------------------------------------
224 SECTION .PD_Initialize
225 ret
226 ;-----------------------------------------------------------------------------
227
228 ;-----------------------------------------------------------------------------
229 SECTION .PD_Shutdown
230 ret
231 ;-----------------------------------------------------------------------------
232
233 ;; Back to code section:
234 section .text
-
+ 6CEECB9422F3D01B04ED2ECB183FB96665FF969087E2967ECCEF2703337401AFB4F0EC91E4B7EFDA625AE4534BA1C3DABA539A1FC794B2E594D7404DDF72399C
m/cpustate.asm
(0 . 0)(1 . 142)
239 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
240 ;; ;;
241 ;; This file is part of 'M', a MIPS system emulator. ;;
242 ;; ;;
243 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
244 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
245 ;; ;;
246 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
247 ;; distribute this software ; Should you use this software for any purpose, ;;
248 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
249 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
250 ;; continue doing so for the indefinite future. In any case, please ;;
251 ;; always : read and understand any software ; verify any PGP signatures ;;
252 ;; that you use - for any purpose. ;;
253 ;; ;;
254 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
256
257 ;-----------------------------------------------------------------------------
258 ; MIPS Processor State.
259 ; Note: PC, nPC, CP0_Status, CP0_Cause, CP0_Compare, are housed in x86 regs.
260 struc MCPU
261 .Regs resd 32 ; The standard MIPS Register Set
262 .LO resd 1 ; Multiplication/division results - Low Half
263 .HI resd 1 ; Multiplication/division results - High Half
264 .CP0_Index resd 1 ; Index into the TLB array
265 .CP0_EntryHi resd 1 ; High-order portion of the TLB entry
266 .CP0_EntryLo0 resd 1 ; Low portion of TLB entry for even-#'d pages
267 .CP0_EntryLo1 resd 1 ; Low portion of TLB entry for odd-#'d pages
268 .CP0_Context resd 1
269 .CP0_Wired resd 1 ; The number of fixed ('wired') TLB entries
270 .CP0_Epc resd 1 ; Exception program counter return address
271 .CP0_BadVAddr resd 1 ; Addr. of most recent addr.-caused exception
272 .CP0_ErrorEpc resd 1 ; Program counter at last exception
273 .CP0_PageMask resd 1 ; Control variable page sizes in TLB entries
274 ;; The TLB:
275 .TLB_Entries resd TLB_ENTRIES_COUNT ; TLB entries (without PFN)
276 .TLB_PFN_Even resd TLB_ENTRIES_COUNT ; TLB PFN0
277 .TLB_PFN_Odd resd TLB_ENTRIES_COUNT ; TLB PFN1
278 endstruc
279 ;-----------------------------------------------------------------------------
280
281 ;-----------------------------------------------------------------------------
282 ; Refer to the N-th TLB Entry:
283 ;-----------------------------------------------------------------------------
284 %define TLB_E(N) dword [M_Base_32 + MCPU.TLB_Entries + 4 * (N)]
285 ; N-th PFN :
286 %define TLB_PFN_E(N) dword [M_Base_32 + MCPU.TLB_PFN_Even + 4 * (N)]
287 %define TLB_PFN_O(N) dword [M_Base_32 + MCPU.TLB_PFN_Odd + 4 * (N)]
288 ;-----------------------------------------------------------------------------
289
290 ;-----------------------------------------------------------------------------
291 section .bss
292 align GRAIN ; MIPS CPU State
293 MIPS_State resb MCPU_size
294 section .text
295 ;-----------------------------------------------------------------------------
296
297 ;-----------------------------------------------------------------------------
298 ; Global 'fast' MIPS State:
299 ; TODO: is it possible to use the upper halves of the 64bit regs for anything?
300 ; ... or entirely worthless from intel's idiocy of 'auto-zero on mov' ?
301 ;-----------------------------------------------------------------------------
302 %define Flag_Reg edi ; Delay, Exception, etc flags
303 %define RAM_Floor rsi ; Physical (x86) address of 1st RAM word
304 %define RAM_Ceiling r8 ; Physical (x86) address of last RAM word
305 %define PC r9d ; Current Program Counter
306 %define nPC r10d ; 'Next' Program Counter
307 %define CP0_Status r11d ; Processor status and control
308 %define CP0_Cause r12d ; Cause of last general exception
309 %define CP0_Count r13d ; Processor cycle count
310 %define CP0_Compare r14d ; Timer interrupt control
311 %define AUX r15d ; Additional TMP for certain ops
312
313 ; TODO: 'Suspend to RAM' routine for all of the above.
314 ;-----------------------------------------------------------------------------
315
316 ;-----------------------------------------------------------------------------
317 ; Access to MIPS Registers that live in MCPU (Emulator State) :
318 ;-----------------------------------------------------------------------------
319 ; Refer to given MIPS special Reg:
320 ;-----------------------------------------------------------------------------
321 %define Sr(N) dword [M_Base_32 + MCPU. %+ N]
322 ;-----------------------------------------------------------------------------
323 ; Refer to Nth Reg:
324 ;-----------------------------------------------------------------------------
325 %define R(N) Sr(Regs + 4 * (N))
326 ;-----------------------------------------------------------------------------
327
328 ;-----------------------------------------------------------------------------
329 ; Update given MIPS Reg # with new value, but always avoid overwriting R(0)
330 ;-----------------------------------------------------------------------------
331 ; TODO: measure if this is actually faster than simply R(31) := 0 every time
332 %macro Wr_Reg 2 ; params: %1: Reg # %2: PC reg with new value
333 xor AUX, AUX ; Clear AUX
334 test %1, %1 ; Set Z if destination reg # is R(0)
335 cmovz %2, AUX ; If Z: Replace written value with zero
336 mov R(%1), %2 ; Regs[rD] := new value
337 ;;;; alt variant:
338 ; mov R(%1), %2 ; Regs[rD] := new value
339 ; mov R(0), 0
340 ;;;; TODO: which is actually faster ?
341 %endmacro
342 ;-----------------------------------------------------------------------------
343
344 ;-----------------------------------------------------------------------------
345 ; Init MIPS CPU:
346 ;-----------------------------------------------------------------------------
347 _cpu_reset:
348 xor eax, eax ; eax := 0
349 mov AUX, eax ; Clear AUX register
350 mov M_Base_64, MIPS_State ; Set RBP to point to MIPS CPU State
351 ;; Init 'fast' MIPS Regs:
352 mov PC, INIT_PC
353 mov nPC, eax
354 mov CP0_Status, eax
355 mov CP0_Cause, eax
356 mov CP0_Count, eax
357 mov CP0_Compare, eax
358 ;; Init 'slow' MIPS Regs:
359 mov ecx, 0
360 _init_reg:
361 mov R(ecx), eax
362 inc ecx
363 cmp ecx, 32
364 jb _init_reg
365 xor ecx, ecx
366 mov Sr(HI), eax
367 mov Sr(LO), eax
368 mov Sr(CP0_Index), eax
369 mov Sr(CP0_EntryHi), eax
370 mov Sr(CP0_EntryLo0), eax
371 mov Sr(CP0_EntryLo1), eax
372 mov Sr(CP0_Context), eax
373 mov Sr(CP0_Wired), eax
374 mov Sr(CP0_Epc), eax
375 mov Sr(CP0_BadVAddr), eax
376 mov Sr(CP0_ErrorEpc), eax
377 Flg_Clear_All ; Reset all misc Flags to 0
378 bts CP0_Status, CP0St_ERL ; Start in kernel mode w/ unmapped useg
379 ret
380 ;-----------------------------------------------------------------------------
-
+ F53ED4111870F8286EF3DE18EB11E03B3ED2EC4575772EF9D3E581D98FDEE7453A1BCD9FDB6054F62FBCD9E4FAF78CC9764A231C02FE94BD06F67D94D616B2B1
m/devices/clock.asm
(0 . 0)(1 . 87)
385 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
386 ;; ;;
387 ;; This file is part of 'M', a MIPS system emulator. ;;
388 ;; ;;
389 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
390 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
391 ;; ;;
392 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
393 ;; distribute this software ; Should you use this software for any purpose, ;;
394 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
395 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
396 ;; continue doing so for the indefinite future. In any case, please ;;
397 ;; always : read and understand any software ; verify any PGP signatures ;;
398 ;; that you use - for any purpose. ;;
399 ;; ;;
400 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
401 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
402
403 ;; TODO: Make the interval programmable. Right now hogs MMIO entirely in vain.
404
405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
406 ;; Interval Clock Device ;;
407 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
408
409 ;-----------------------------------------------------------------------------
410 ; Interval Clock MMIO:
411 DECLARE_BUS_DEVICE CLOCK, 0x420, 0x42F
412 ;-----------------------------------------------------------------------------
413
414 ;-----------------------------------------------------------------------------
415 ; Interval Clock IRQ:
416 ;-----------------------------------------------------------------------------
417 %define CLOCK_IRQ 3 ; UART0 Receiver Slave IRQ
418 ;-----------------------------------------------------------------------------
419
420 ;-----------------------------------------------------------------------------
421 ; Interval Clock State
422 ;-----------------------------------------------------------------------------
423 section .bss
424 CLOCK_Die resd 1 ; Shutdown Trigger
425 ;-----------------------------------------------------------------------------
426
427 section .text
428
429 ;-----------------------------------------------------------------------------
430 _PD_Read_Word_CLOCK: ; Word reads from CLOCK always 0
431 xor eax, eax
432 ret ; Fin.
433 ;-----------------------------------------------------------------------------
434 _PD_Write_Word_CLOCK: ; Word writes to CLOCK do nothing!
435 ret
436 ;-----------------------------------------------------------------------------
437 _PD_Read_Byte_CLOCK:
438 xor eax, eax ; Read Byte from CLOCK: always 0
439 ret
440 ;-----------------------------------------------------------------------------
441 _PD_Write_Byte_CLOCK:
442 ret ; Fin.
443 ;-----------------------------------------------------------------------------
444 _Device_Init_CLOCK:
445 mov rdi, _Clock_Slave ; Clock Slave
446 call _Create_Thread ; Start the Clock Slave Thread
447 ret
448 ;-----------------------------------------------------------------------------
449 _Device_Shutdown_CLOCK: ; Shutdown
450 mov dword [CLOCK_Die], 0x01 ; Ask (unblocked) slave to die
451 ret
452 ;-----------------------------------------------------------------------------
453
454 ;-----------------------------------------------------------------------------
455 _Clock_Slave:
456 mov rax, _clock_interval_ts ; Set the 'nanosleep' interval
457 call _Nano_Sleep ; Sleep for the given interval (nS)
458 SetSlaveIRQ CLOCK_IRQ ; Invoke timer slave interrupt
459 cmp dword [CLOCK_Die], 0x01 ; time to die?
460 jne _Clock_Slave ; if not, keep going.
461 jmp _exit_thread ; terminate thread
462 ;-----------------------------------------------------------------------------
463
464 section .rodata
465
466 ;-----------------------------------------------------------------------------
467 ; TS for Clock Slave interval:
468 _clock_interval_ts:
469 dq 0 ; seconds
470 dq TIMER_SLAVE_PERIOD ; nanoseconds
471 ;-----------------------------------------------------------------------------
-
+ BA3687D23DE5CCF60651014123DD59FE60B32ECBF2101D6165F7A06448D1E031B340AC7BAA886BCDFA375FD971100D45E2D2CBB8B1CAF21D761949CB31F70864
m/devices/devices.asm
(0 . 0)(1 . 29)
476 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
477 ;; ;;
478 ;; This file is part of 'M', a MIPS system emulator. ;;
479 ;; ;;
480 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
481 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
482 ;; ;;
483 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
484 ;; distribute this software ; Should you use this software for any purpose, ;;
485 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
486 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
487 ;; continue doing so for the indefinite future. In any case, please ;;
488 ;; always : read and understand any software ; verify any PGP signatures ;;
489 ;; that you use - for any purpose. ;;
490 ;; ;;
491 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
492 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
493
494 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
495 ;; All Memory-Mapped Devices MUST be included here (and only here),
496 ;; in DESCENDING order of their MMIO Address range's position in MMIO Segment:
497 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
498
499 %include "rtc.asm" ; Real-Time Clock Device (MMIO: 0x430 - 0x434)
500 %include "clock.asm" ; Interval Clock Device (MMIO: 0x420 - 0x42F; IRQ 3)
501 %include "power.asm" ; Power Supply (MMIO: 0x410 - 0x410)
502 %include "uart.asm" ; UART0 Console (MMIO: 0x3F8 - 0x40C; IRQ 2)
503
504 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
+ C4EF1F09A367612089DE366E1D75F980928A48C40B2B30CB50FAE20439CA5FBF59AD0AA71AA231AA0AA75833BB71DE1F241A8A6F3FBD747A6BF91C17489A5D4C
m/devices/power.asm
(0 . 0)(1 . 58)
509 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
510 ;; ;;
511 ;; This file is part of 'M', a MIPS system emulator. ;;
512 ;; ;;
513 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
514 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
515 ;; ;;
516 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
517 ;; distribute this software ; Should you use this software for any purpose, ;;
518 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
519 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
520 ;; continue doing so for the indefinite future. In any case, please ;;
521 ;; always : read and understand any software ; verify any PGP signatures ;;
522 ;; that you use - for any purpose. ;;
523 ;; ;;
524 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
525 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
526
527 ;; TODO: 'warm boot' command. Right now, 'shutdown' is the only supported cmd.
528
529 ;;;;;;;;;;;;;;;;;;;;;;;;;
530 ;; Power Supply Device ;;
531 ;;;;;;;;;;;;;;;;;;;;;;;;;
532
533 ;-----------------------------------------------------------------------------
534 ;; Power Supply:
535 DECLARE_BUS_DEVICE POWER, 0x410, 0x410
536 ;-----------------------------------------------------------------------------
537
538 ;-----------------------------------------------------------------------------
539 %define POWER_CMD_SHUTDOWN 0x01 ; 'Power off' immediately.
540 ;-----------------------------------------------------------------------------
541
542 ;-----------------------------------------------------------------------------
543 _PD_Read_Word_POWER: ; Word reads from POWER: always 0
544 xor eax, eax
545 ret ; Fin.
546 ;-----------------------------------------------------------------------------
547 _PD_Write_Word_POWER: ; Word writes to POWER do nothing!
548 ret
549 ;-----------------------------------------------------------------------------
550 _PD_Read_Byte_POWER:
551 xor eax, eax ; Read Byte from POWER: always 0
552 ret
553 ;-----------------------------------------------------------------------------
554 _PD_Write_Byte_POWER:
555 cmp dl, 1 ; 1 == shutdown
556 jne _PD_Write_Byte_POWER_No_Shutdown ; if != 1, do not shut down
557 Flg_On Shutdown ; Set the Shutdown flag.
558 _PD_Write_Byte_POWER_No_Shutdown:
559 ret ; Fin.
560 ;-----------------------------------------------------------------------------
561 _Device_Init_POWER: ; No init needed
562 ret
563 ;-----------------------------------------------------------------------------
564 _Device_Shutdown_POWER: ; Nothing needed
565 ret
566 ;-----------------------------------------------------------------------------
-
+ 1232CD80AD35A8A65C9767C3A9CDBE9CE5024F93F609B1F2AF4CE225B436366E5B31596F698344AB45B25633382C983AA839B0CE017976614186021A46F11FAB
m/devices/rtc.asm
(0 . 0)(1 . 70)
571 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
572 ;; ;;
573 ;; This file is part of 'M', a MIPS system emulator. ;;
574 ;; ;;
575 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
576 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
577 ;; ;;
578 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
579 ;; distribute this software ; Should you use this software for any purpose, ;;
580 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
581 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
582 ;; continue doing so for the indefinite future. In any case, please ;;
583 ;; always : read and understand any software ; verify any PGP signatures ;;
584 ;; that you use - for any purpose. ;;
585 ;; ;;
586 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
587 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
588
589 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
590 ;; Real-Time Clock Device ;;
591 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
592
593 ;-----------------------------------------------------------------------------
594 ;; Real-Time Clock MMIO:
595 DECLARE_BUS_DEVICE RTC, 0x430, 0x434
596 ;-----------------------------------------------------------------------------
597
598 ;-----------------------------------------------------------------------------
599 ; Epoch Time: 'Sec. since 00:00:00 Thursday, 1 January 1970'
600 %define RTC_REG_EPOCH_LO 0 ; Lower 32 bits of RTC Epoch Time
601 %define RTC_REG_EPOCH_HI 4 ; Upper 32 bits of RTC Epoch Time
602 ;-----------------------------------------------------------------------------
603
604 ;-----------------------------------------------------------------------------
605 _PD_Read_Word_RTC: ; Word reads from RTC:
606 sub eax, RTC_BASE ; Adjust for base of RTC MMIO
607 cmp eax, RTC_REG_EPOCH_LO ; Word at 0x0: Low 32 bits of time
608 je .rtc_epoch_low_word
609 cmp eax, RTC_REG_EPOCH_HI ; Word at 0x4: High 32 bits of time
610 je .rtc_epoch_high_word
611 .rtc_undefined_reg: ; If unknown reg (how?) :
612 ACHTUNG "Read Unknown RTC Reg?"
613 xor eax, eax ; ... return 0 always.
614 ret ; Fin.
615 .rtc_epoch_low_word: ; Get LOW 32 bits of Epoch Time :
616 call _Get_Epoch_Time ; Retrieve epoch time from host
617 mov eax, edx ; eax := low word
618 ret ; Fin.
619 .rtc_epoch_high_word: ; Get HIGH 32 bits of Epoch Time :
620 call _Get_Epoch_Time ; Retrieve epoch time from host
621 shr rdx, 32 ; get high word
622 mov eax, edx ; eax := high word
623 ret ; Fin.
624 ;-----------------------------------------------------------------------------
625 _PD_Write_Word_RTC: ; Word writes to RTC do nothing!
626 ret
627 ;-----------------------------------------------------------------------------
628 _PD_Read_Byte_RTC:
629 xor eax, eax ; Read Byte from RTC: always 0
630 ret
631 ;-----------------------------------------------------------------------------
632 _PD_Write_Byte_RTC:
633 ret ; Fin.
634 ;-----------------------------------------------------------------------------
635 _Device_Init_RTC: ; Needs no init.
636 ret
637 ;-----------------------------------------------------------------------------
638 _Device_Shutdown_RTC: ; Needs no shutdown.
639 ret
640 ;-----------------------------------------------------------------------------
-
+ 3C2674A38D90D63804BB65359BBF557C2ABA45C46F55158975ACB06508EC610D7DAE55E9F29CAC537BCA67D3C2E7645D3F7425FC6E3127C4304B035D5D786013
m/devices/uart.asm
(0 . 0)(1 . 449)
645 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
646 ;; ;;
647 ;; This file is part of 'M', a MIPS system emulator. ;;
648 ;; ;;
649 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
650 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
651 ;; ;;
652 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
653 ;; distribute this software ; Should you use this software for any purpose, ;;
654 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
655 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
656 ;; continue doing so for the indefinite future. In any case, please ;;
657 ;; always : read and understand any software ; verify any PGP signatures ;;
658 ;; that you use - for any purpose. ;;
659 ;; ;;
660 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
661 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662
663 ;;;;;;;;;;;;;;;;;;;;;;;;;
664 ;; UART Console Device ;;
665 ;;;;;;;;;;;;;;;;;;;;;;;;;
666
667 ;-----------------------------------------------------------------------------
668 ; Console UART MMIO:
669 DECLARE_BUS_DEVICE UART, 0x3F8, 0x40C
670 ;-----------------------------------------------------------------------------
671
672 ;-----------------------------------------------------------------------------
673 ; Console UART IRQ:
674 ;-----------------------------------------------------------------------------
675 %define UART0_IRQ 2 ; UART0 Receiver Slave IRQ
676 ;-----------------------------------------------------------------------------
677
678 section .text
679
680 ;-----------------------------------------------------------------------------
681 _PD_Read_Word_UART: ; Word reads from UART: always 0
682 xor eax, eax
683 ret ; Fin.
684 ;-----------------------------------------------------------------------------
685 _PD_Write_Word_UART: ; Word writes to POWER do nothing!
686 ret
687 ;-----------------------------------------------------------------------------
688 _PD_Read_Byte_UART: ; Read Byte from UART
689 call _UART_Read_Reg ; Read this byte from UART
690 mov eax, edx ; Return the resulting byte.
691 ret ; Fin.
692 ;-----------------------------------------------------------------------------
693 _PD_Write_Byte_UART: ; Write Byte to UART
694 call _UART_Write_Reg ; write this byte to UART
695 ret ; Fin.
696 ;-----------------------------------------------------------------------------
697 _Device_Init_UART:
698 call _Cure_TTY ; Cure the tty:
699 call _UART_Reset ; Reset the UART
700 mov rdi, _UART_Slave ; UART Slave
701 call _Create_Thread ; Start the UART Slave Thread
702 ret
703 ;-----------------------------------------------------------------------------
704 _Device_Shutdown_UART: ; Nothing needed
705 mov dword [UART_Die], 0x01 ; Ask (unblocked) slave to die
706 call _Uncure_TTY ; bring back the old tty settings, for clean shell
707 ret
708 ;-----------------------------------------------------------------------------
709
710
711 ;-----------------------------------------------------------------------------
712 ;; UART State
713 ;-----------------------------------------------------------------------------
714 section .bss
715 UART0 resb UART_State_size ; UART-0 State
716 UART_Die resd 1 ; Shutdown Trigger
717 ;-----------------------------------------------------------------------------
718
719 section .text
720
721 ;-----------------------------------------------------------------------------
722 ; Slave Thread which connects UART0 to linux console
723 ;-----------------------------------------------------------------------------
724 _UART_Slave:
725 call _Read_Char_Blocking
726 mov dl, byte [IOBUF]
727 call _UART_Receive_Byte ; put DL in the UART receiver queue
728 SetSlaveIRQ UART0_IRQ ; trigger the slave IRQ
729 cmp dword [UART_Die], 0x01 ; time to die?
730 jne _UART_Slave ; if not, keep going.
731 jmp _exit_thread ; terminate thread
732 ;-----------------------------------------------------------------------------
733
734 ;-----------------------------------------------------------------------------
735 ; UARTism
736 ;-----------------------------------------------------------------------------
737 ;; UART State
738 struc UART_State
739 .LCR resb 1 ; Line Control
740 .LSR resb 1 ; Line Status
741 .MSR resb 1 ; Modem Status
742 .IIR resb 1 ; Interrupt ID
743 .IER resb 1 ; Interrupt Enable
744 .DLL resb 1 ;
745 .DLH resb 1 ;
746 .FCR resb 1 ; FIFO Control
747 .MCR resb 1 ; Modem Control
748 .SCR resb 1 ; Modem Control
749 ;; FIFO:
750 .FIFO resb 32 ; The FIFO itself
751 .FIFO_First resb 1 ; index of 1st byte in the FIFO
752 .FIFO_Last resb 1 ; index of last byte in the FIFO
753 .FIFO_Count resb 1 ; number of bytes in the FIFO
754 endstruc
755 ;-----------------------------------------------------------------------------
756
757 %define UART_LSR_DATA_READY 0x1
758 %define UART_LSR_FIFO_EMPTY 0x20
759 %define UART_LSR_TRANSMITTER_EMPTY 0x40
760
761 ; Enable Transmitter holding register int.
762 %define UART_IER_THRI 0x02
763
764 ; Enable receiver data interrupt
765 %define UART_IER_RDI 0x01
766
767 ; Modem status interrupt (Low priority)
768 %define UART_IIR_MSI 0x00
769
770 %define UART_IIR_NO_INT 0x01
771
772 ; Transmitter holding register empty
773 %define UART_IIR_THRI 0x02
774
775 ; Receiver data interrupt
776 %define UART_IIR_RDI 0x04
777
778 ; Receiver line status interrupt (High p.)
779 %define UART_IIR_RLSI 0x06
780
781 ; Character timeout
782 %define UART_IIR_CTI 0x0c
783
784 ; Divisor latch access bit
785 %define UART_LCR_DLAB 0x80
786
787 ; R/W: Divisor Latch Low, DLAB=1
788 %define UART_DLL 0
789
790 ; R/W: Divisor Latch High, DLAB=1
791 %define UART_DLH 1
792
793 ; R/W: Interrupt Enable Register
794 %define UART_IER 1
795
796 ; R: Interrupt ID Register
797 %define UART_IIR 2
798
799 ; W: FIFO Control Register
800 %define UART_FCR 2
801
802 ; R/W: Line Control Register
803 %define UART_LCR 3
804
805 ; W: Modem Control Register
806 %define UART_MCR 4
807
808 ; R: Line Status Register
809 %define UART_LSR 5
810
811 ; R: Modem Status Register
812 %define UART_MSR 6
813
814 ; R/W:
815 %define UART_SCR 7
816 ;-----------------------------------------------------------------------------
817
818 ;-----------------------------------------------------------------------------
819 ;; Access to UART regs:
820 %define U0r(R) byte [UART0 + UART_State. %+ R]
821 ;-----------------------------------------------------------------------------
822 ;; Clear FIFO
823 ;-----------------------------------------------------------------------------
824 _UART_FIFO_Clear:
825 mov U0r(FIFO_Last), 0
826 mov U0r(FIFO_First), 0
827 mov U0r(FIFO_Count), 0
828 ret
829 ;-----------------------------------------------------------------------------
830
831 ;-----------------------------------------------------------------------------
832 ;; Take a byte from the UART FIFO. Byte will be in DL.
833 ;-----------------------------------------------------------------------------
834 _UART_FIFO_Get:
835 xor edx, edx ; edx := 0
836 cmp U0r(FIFO_Count), 0 ; is FIFO nonempty?
837 je _UART_FIFO_Get_Nope ; ... if empty, skip and return 0
838 ;; if FIFO is nonempty:
839 xor eax, eax ; eax := 0
840 mov al, U0r(FIFO_First) ; al := fifo_first
841 mov dl, U0r(FIFO + eax) ; dl := FIFO[al]
842 inc eax ; eax := eax + 1
843 and eax, 0x1F ; eax := eax & 0x1f
844 mov U0r(FIFO_First), al ; fifo_first := al
845 mov al, U0r(FIFO_Count) ; al := fifo_count
846 test eax, eax ; is al 0 ?
847 jz _UART_FIFO_Get_Nope ; ... if 0, skip and do not update count
848 dec eax ; eax := eax - 1
849 mov U0r(FIFO_Count), al ; fifo_count := al
850 _UART_FIFO_Get_Nope:
851 ret
852 ;-----------------------------------------------------------------------------
853
854 ;-----------------------------------------------------------------------------
855 ;; Reset UART-0
856 ;-----------------------------------------------------------------------------
857 _UART_Reset:
858 mov U0r(LCR), 3
859 mov U0r(LSR), UART_LSR_TRANSMITTER_EMPTY | UART_LSR_FIFO_EMPTY
860 mov U0r(MSR), 0
861 mov U0r(IIR), UART_IIR_NO_INT
862 mov U0r(IER), 0
863 mov U0r(DLL), 0
864 mov U0r(DLH), 0
865 mov U0r(FCR), 0
866 mov U0r(MCR), 0
867 mov U0r(SCR), 0
868 call _UART_FIFO_Clear ; zap the FIFO
869 ret
870 ;-----------------------------------------------------------------------------
871 ;; Update UART IRQ
872 ;-----------------------------------------------------------------------------
873 _UART_IRQ:
874 test U0r(LSR), UART_LSR_DATA_READY
875 jz _UART_IRQ_Not_RDI
876 test U0r(IER), UART_IER_RDI
877 jz _UART_IRQ_Not_RDI
878 _UART_IRQ_RDI:
879 mov U0r(IIR), UART_IIR_RDI ; IIR=UART_IIR_RDI
880 jmp _UART_IRQ_Maybe_Pending ; See if interrupt pending
881 _UART_IRQ_Not_RDI:
882 test U0r(LSR), UART_LSR_FIFO_EMPTY
883 jz _UART_IRQ_Not_THRI
884 test U0r(IER), UART_IER_THRI
885 jz _UART_IRQ_Not_THRI
886 _UART_IRQ_THRI:
887 mov U0r(IIR), UART_IIR_THRI ; IIR=UART_IIR_THRI
888 jmp _UART_IRQ_Maybe_Pending ; See if interrupt pending
889 _UART_IRQ_Not_THRI:
890 mov U0r(IIR), UART_IIR_NO_INT ; IIR=UART_IIR_NO_INT
891 _UART_IRQ_Maybe_Pending: ; See if interrupt pending
892 ;; see if interrupt pending
893 cmp U0r(IIR), UART_IIR_NO_INT ; IIR==UART_IIR_NO_INT ?
894 jne _UART_IRQ_Pending ; if !=, interrupt is pending
895 _UART_IRQ_Not_Pending: ; interrupt is not pending:
896 ClrIRQ UART0_IRQ
897 ret
898 _UART_IRQ_Pending: ; interrupt is pending:
899 SetIRQ UART0_IRQ
900 ret
901 ;-----------------------------------------------------------------------------
902
903 ;-----------------------------------------------------------------------------
904 ;; Place a byte (DL) into the UART's receiver buffer.
905 ; TODO: mutex?
906 ;-----------------------------------------------------------------------------
907 _UART_Receive_Byte:
908 xor eax, eax ; eax := 0
909 mov al, U0r(FIFO_Last) ; al := fifo_last
910 mov U0r(FIFO + eax), dl ; FIFO[al] := dl
911 inc eax ; eax := eax + 1
912 and eax, 0x1F ; eax := eax & 0x1f
913 mov U0r(FIFO_Last), al ; fifo_last := al
914 mov al, U0r(FIFO_Count) ; eax := fifo_count
915 inc eax ; eax := eax + 1
916 mov edx, 32 ; edx := 32
917 cmp eax, edx ; is eax > 32 ?
918 cmovg eax, edx ; ... if yes, eax := 32
919 mov U0r(FIFO_Count), al ; fifo_count := al
920 or U0r(LSR), UART_LSR_DATA_READY ; set the 'ready' flag
921 call _UART_IRQ ; update IRQ
922 ret
923 ;-----------------------------------------------------------------------------
924
925 ;-----------------------------------------------------------------------------
926 ;; Read UART Register. Offset in EAX, result in DL.
927 ;-----------------------------------------------------------------------------
928 _UART_Read_Reg:
929 xor edx, edx ; result := 0
930 sub eax, UART_BASE ; Adjust for base of UART
931 and eax, 0x7 ; Adjusted offset is a 4-bit quantity
932 test U0r(LCR), UART_LCR_DLAB
933 jz _UART_Read_Reg_Not_DLAB
934 _UART_Read_Reg_DLAB:
935 cmp eax, UART_DLL ; offset=DLL?
936 je _UART_Read_Reg_DLAB_DLL
937 cmp eax, UART_DLH ; offset=DLH?
938 je _UART_Read_Reg_DLAB_DLH
939 jmp _UART_Read_Reg_Not_DLAB ; neither of these
940 _UART_Read_Reg_DLAB_DLL:
941 mov dl, U0r(DLL) ; return DLL
942 ret
943 _UART_Read_Reg_DLAB_DLH:
944 mov dl, U0r(DLH) ; return DLH
945 ret
946 _UART_Read_Reg_Not_DLAB:
947 cmp eax, 0 ; offset=0 ?
948 je _UART_Read_Reg_0
949 cmp eax, UART_IER ; offset=IER ?
950 je _UART_Read_Reg_IER
951 cmp eax, UART_MSR ; offset=MSR ?
952 je _UART_Read_Reg_MSR
953 cmp eax, UART_MCR ; offset=MCR ?
954 je _UART_Read_Reg_MCR
955 cmp eax, UART_IIR ; offset=IIR ?
956 je _UART_Read_Reg_IIR
957 cmp eax, UART_LCR ; offset=LCR ?
958 je _UART_Read_Reg_LCR
959 cmp eax, UART_LSR ; offset=LSR ?
960 je _UART_Read_Reg_LSR
961 cmp eax, UART_SCR ; offset=SCR ?
962 je _UART_Read_Reg_SCR
963 ACHTUNG "Bad UART Read Command." ; TODO: print detail
964 ret
965
966 _UART_Read_Reg_0:
967 cmp U0r(FIFO_Count), 0 ; is FIFO nonempty?
968 je _UART_Read_Reg_0_Empty ; ... if empty, skip
969 ;; FIFO is not empty:
970 call _UART_FIFO_Get ; get byte from FIFO
971 and U0r(LSR), ~UART_LSR_DATA_READY ; lower 'ready' flag
972 cmp U0r(FIFO_Count), 0 ; is FIFO still nonempty?
973 je _UART_Read_Reg_0_Empty ; ... if empty, leave 'ready' flag down
974 ;; FIFO still has data:
975 or U0r(LSR), UART_LSR_DATA_READY ; else, raise the 'ready' flag.
976 _UART_Read_Reg_0_Empty:
977 call _UART_IRQ ; update IRQ
978 ret ; return DL
979
980 _UART_Read_Reg_IER:
981 mov dl, U0r(IER)
982 and edx, 0xF
983 ret ; return IER & 0xF
984
985 _UART_Read_Reg_MSR:
986 mov dl, U0r(MSR)
987 ret ; return MSR
988
989 _UART_Read_Reg_MCR:
990 mov dl, U0r(MCR)
991 ret ; return MCR
992
993 _UART_Read_Reg_IIR:
994 mov dl, U0r(IIR)
995 ret ; return IIR
996
997 _UART_Read_Reg_LCR:
998 mov dl, U0r(LCR)
999 ret ; return LCR
1000
1001 _UART_Read_Reg_LSR:
1002 cmp U0r(FIFO_Count), 0 ; is FIFO nonempty?
1003 je _UART_Read_Reg_LSR_Empty ; if empty, go to 'empty'
1004 ;; FIFO is not empty:
1005 or U0r(LSR), UART_LSR_DATA_READY ; raise the 'ready' flag.
1006 jmp _UART_Read_Reg_LSR_Done ; return
1007 _UART_Read_Reg_LSR_Empty:
1008 and U0r(LSR), ~UART_LSR_DATA_READY ; lower the 'ready' flag
1009 _UART_Read_Reg_LSR_Done:
1010 mov dl, U0r(LSR)
1011 ret ; return LSR
1012
1013 _UART_Read_Reg_SCR:
1014 mov dl, U0r(SCR)
1015 ret ; return SCR
1016 ;-----------------------------------------------------------------------------
1017
1018 ;-----------------------------------------------------------------------------
1019 ;; Write UART Register. Offset in EAX, payload in DL.
1020 ;-----------------------------------------------------------------------------
1021 _UART_Write_Reg:
1022 sub eax, UART_BASE ; Adjust for base of UART
1023 and eax, 0x7 ; Adjusted offset is a 4-bit quantity
1024 test U0r(LCR), UART_LCR_DLAB
1025 jz _UART_Write_Reg_Not_DLAB
1026 _UART_Write_Reg_DLAB:
1027 cmp eax, UART_DLL ; offset=DLL?
1028 je _UART_Write_Reg_DLAB_DLL
1029 cmp eax, UART_DLH ; offset=DLH?
1030 je _UART_Write_Reg_DLAB_DLH
1031 jmp _UART_Write_Reg_Not_DLAB ; neither of these
1032 _UART_Write_Reg_DLAB_DLL:
1033 mov U0r(DLL), dl ; write DLL
1034 ret
1035 _UART_Write_Reg_DLAB_DLH:
1036 mov U0r(DLH), dl ; write DLH
1037 ret
1038 _UART_Write_Reg_Not_DLAB:
1039 cmp eax, 0 ; offset=0 ?
1040 je _UART_Write_Reg_0
1041 cmp eax, UART_IER ; offset=IER?
1042 je _UART_Write_Reg_IER
1043 cmp eax, UART_FCR ; offset=FCR?
1044 je _UART_Write_Reg_FCR
1045 cmp eax, UART_LCR ; offset=LCR?
1046 je _UART_Write_Reg_LCR
1047 cmp eax, UART_MCR ; offset=MCR?
1048 je _UART_Write_Reg_MCR
1049 cmp eax, UART_SCR ; offset=SCR?
1050 je _UART_Write_Reg_SCR
1051 ACHTUNG "Bad UART Write Command." ; TODO: print detail
1052 ret
1053
1054 _UART_Write_Reg_0:
1055 and U0r(LSR), ~UART_LSR_FIFO_EMPTY
1056 test U0r(MCR), (1 << 4)
1057 jz _UART_Write_Reg_0_Not_Loopback
1058 _UART_Write_Reg_0_Loopback:
1059 call _UART_Receive_Byte ; put DL in the receiver FIFO
1060 jmp _UART_Write_Reg_0_Fin ; wrap up
1061 _UART_Write_Reg_0_Not_Loopback: ; if NOT loopback :
1062 call _Write_Char ; ... then write char in DL to console
1063 _UART_Write_Reg_0_Fin:
1064 or U0r(LSR), UART_LSR_FIFO_EMPTY ; mark the send buffer as empty
1065 call _UART_IRQ ; refresh IRQ
1066 ret ; fin
1067
1068 _UART_Write_Reg_IER:
1069 and edx, 0xF ; 4-bit qty
1070 mov U0r(IER), dl ; IER := dl & 0xF
1071 call _UART_IRQ ; refresh IRQ
1072 ret ; fin
1073
1074 _UART_Write_Reg_FCR:
1075 mov U0r(FCR), dl ; FCR := dl
1076 test dl, 0x2 ; if FCR & 2:
1077 jz _UART_Write_Reg_FCR_No_Clear
1078 call _UART_FIFO_Clear ; ... then zap the FIFO.
1079 _UART_Write_Reg_FCR_No_Clear:
1080 ret
1081
1082 _UART_Write_Reg_LCR:
1083 mov U0r(LCR), dl ; LCR := dl
1084 ret ; fin
1085
1086 _UART_Write_Reg_MCR:
1087 mov U0r(MCR), dl ; MCR := dl
1088 ret ; fin
1089
1090 _UART_Write_Reg_SCR:
1091 mov U0r(SCR), dl ; SCR := dl
1092 ret ; fin
1093 ;-----------------------------------------------------------------------------
-
+ A7D2BE62ABFD1319DBAFAA5F8EEDD8718C3364A59D89E89C611D0A95D04BA6D81D089E93A65853F85FF3FDD45B413C2C582CBE9E7B082E40F18F206D2CAFDBB1
m/flags.asm
(0 . 0)(1 . 61)
1098 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1099 ;; ;;
1100 ;; This file is part of 'M', a MIPS system emulator. ;;
1101 ;; ;;
1102 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1103 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1104 ;; ;;
1105 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1106 ;; distribute this software ; Should you use this software for any purpose, ;;
1107 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1108 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1109 ;; continue doing so for the indefinite future. In any case, please ;;
1110 ;; always : read and understand any software ; verify any PGP signatures ;;
1111 ;; that you use - for any purpose. ;;
1112 ;; ;;
1113 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1114 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1115
1116 ;-----------------------------------------------------------------------------
1117 ; Emulator Flags (kept in Flag_Reg)
1118 ;-----------------------------------------------------------------------------
1119 %define InDelaySlot 0
1120 %define RunningDelaySlot 1
1121 %define Waiting 2
1122 %define LL_Bit 3
1123 %define IsWriting 4
1124 %define ExcWasTLBNoMatch 5
1125 %define Shutdown 6
1126 ;-----------------------------------------------------------------------------
1127 ; Set a given Flag:
1128 %macro Flg_On 1
1129 bts Flag_Reg, %1 ; Set the given Flag.
1130 %endmacro
1131 ;-----------------------------------------------------------------------------
1132 ; Clear a given Flag:
1133 %macro Flg_Off 1
1134 btr Flag_Reg, %1 ; Clear the given Flag.
1135 %endmacro
1136
1137 %define Flg_GOF Flg_Off ; BTR inst also gives the old value
1138 ;-----------------------------------------------------------------------------
1139 ; Get a given Flag (into CF) :
1140 %macro Flg_Get 1
1141 bt Flag_Reg, %1 ; Read the given Flag.
1142 %endmacro
1143 ;-----------------------------------------------------------------------------
1144 ; Clear all Flags:
1145 %macro Flg_Clear_All 0
1146 xor Flag_Reg, Flag_Reg ; Clear all Flags.
1147 %endmacro
1148 ;-----------------------------------------------------------------------------
1149 ; Copy one Flag to another Flag. Uses EAX for scratch.
1150 %macro Flg_Cpy 2 ; %1 : destination Flag; %2 : source Flag.
1151 Flg_Off %1 ; Clear the Destination Flag
1152 xor eax, eax ; eax := 0
1153 Flg_Get %2 ; CF := Source Flag
1154 setc al ; AL := CF (value of Source Flag)
1155 shl eax, %1 ; Slide this bit up to destination pos.
1156 or Flag_Reg, eax ; Write the destination Flag
1157 %endmacro
1158 ;-----------------------------------------------------------------------------
-
+ 46635728670946901EDCA4062D650365295341CF87401AC4FBB7F78423FAF76B5C246A07EA8E5FC76FCD4B49FF669102F556F47F7C5A247670FD00FFEE665B80
m/i_decode.asm
(0 . 0)(1 . 284)
1163 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1164 ;; ;;
1165 ;; This file is part of 'M', a MIPS system emulator. ;;
1166 ;; ;;
1167 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1168 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1169 ;; ;;
1170 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1171 ;; distribute this software ; Should you use this software for any purpose, ;;
1172 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1173 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1174 ;; continue doing so for the indefinite future. In any case, please ;;
1175 ;; always : read and understand any software ; verify any PGP signatures ;;
1176 ;; that you use - for any purpose. ;;
1177 ;; ;;
1178 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1179 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1180
1181 ;-----------------------------------------------------------------------------
1182 ; Helper macros for MIPS instruction operands.
1183 ; All presume that current MIPS instruction is found in r_I.
1184 ; Note that variable shifts on x86 require slide amount to reside in CL.
1185 ;-----------------------------------------------------------------------------
1186
1187 ;-----------------------------------------------------------------------------
1188 ; These constants are fixed for the MIPS32 architecture and will NEVER change:
1189 ;-----------------------------------------------------------------------------
1190 ; Masks for Instruction Fields:
1191 %define rD_Mask 0xF800 ; Mask for rD Field
1192 %define rS_Mask 0x3E00000 ; Mask for rS Field
1193 %define rT_Mask 0x1F0000 ; Mask for rT Field
1194 %define Imm_Mask 0xFFFF ; Mask for Imm Field
1195 %define Shamt_Mask 0x7C0 ; Mask for Shamt Field
1196 %define J_Mask 0x3FFFFFF ; Mask for J Field
1197 %define Q_Mask 0x7 ; Mask for Q Field (MFC0/MTC0 instructions)
1198 ;-----------------------------------------------------------------------------
1199 ; Shifts for Instruction Fields (Imm doesn't need one) :
1200 %define rD_Shr 11 ; Right Shift for rD Field
1201 %define rS_Shr 21 ; Right Shift for rS Field
1202 %define rT_Shr 16 ; Right Shift for rT Field
1203 %define Shamt_Shr 6 ; Right Shift for Shamt Field
1204 %define J_Shl 2 ; Left Shift for J Field
1205 ;-----------------------------------------------------------------------------
1206
1207 ;-----------------------------------------------------------------------------
1208 ; Register Placements
1209 ;-----------------------------------------------------------------------------
1210
1211 ; To point to MIPS state:
1212 %define M_Base_64 rbp ; Pointer to base of MIPS data structure
1213 %define M_Base_32 ebp ; 32-bit component of above
1214
1215 ;-----------------------------------------------------------------------------
1216 ; Scratch Registers used inside Opcodes:
1217 ;-----------------------------------------------------------------------------
1218 %define rD eax ; Where to extract rD Field
1219 %define Imm rD ; Where IType's Imm goes (they have no rD)
1220 %define JTarg rD ; Where JType's J field goes
1221
1222 ; x86 is braindamaged and DEMANDS variable shift slides in CL. So rS is ECX.
1223 %define rS ecx ; Where to extract rS Field
1224 %define rS_LowByte cl ; Low byte of rS, for some 'flag' ops
1225 %define r_Shamt rS ; must be also this (see above)
1226 %define r_Q rS ; Q field in the coprocessor instructions
1227
1228 %define rT ebx ; Where to extract rT Field
1229
1230 ; Scratch Register for intermediates:
1231 %define TMP edx ; Scratch register used in all ops
1232 %define TMP_LowByte dl ; Low byte of TMP, for some 'flag' ops
1233
1234 ; After we decode all fields, we no longer need the original instruction :
1235 %define r_I TMP ; Copy of currently-executing instruction
1236 ;-----------------------------------------------------------------------------
1237
1238 ;-----------------------------------------------------------------------------
1239 ; Instruction Field Manipulations. Arranged so as to satisfy the x86 pipeline.
1240 ;-----------------------------------------------------------------------------
1241
1242 ;-----------------------------------------------------------------------------
1243 ; Extract rD, rS, rT fields from the currently-executing MIPS instruction
1244 ; For instructions encoded as ???? ??ss ssst tttt dddd d??? ???? ????
1245 ;-----------------------------------------------------------------------------
1246 %macro RType 0 ; no params
1247 mov rD, rD_Mask ; Mask for rD Field
1248 mov rS, rS_Mask ; Mask for rS Field
1249 mov rT, rT_Mask ; Mask for rT Field
1250 and rD, r_I ; Mask orig. inst. to get rD Field
1251 and rS, r_I ; Mask orig. inst. to get rS Field
1252 and rT, r_I ; Mask orig. inst. to get rT Field
1253 shr rD, rD_Shr ; rD is now rD Index
1254 shr rS, rS_Shr ; rS is now rS Index
1255 shr rT, rT_Shr ; rT is now rT Index
1256 %endmacro
1257 ;-----------------------------------------------------------------------------
1258
1259 ;-----------------------------------------------------------------------------
1260 ; Extract only rS field from the currently-executing MIPS instruction
1261 ; For instructions encoded as ???? ??ss sss? ???? ???? ???? ???? ????
1262 ;-----------------------------------------------------------------------------
1263 %macro RType_S_Only 0 ; no params
1264 mov rS, rS_Mask ; Mask for rS Field
1265 and rS, r_I ; Mask orig. inst. to get rS Field
1266 shr rS, rS_Shr ; rS is now rS Index
1267 %endmacro
1268 ;-----------------------------------------------------------------------------
1269
1270 ; Works same
1271 %define IType_S_Only RType_S_Only
1272
1273 ;-----------------------------------------------------------------------------
1274 ; Extract only rS and rT fields from the currently-executing MIPS instruction
1275 ; For instructions encoded as ???? ??ss ssst tttt ???? ???? ???? ????
1276 ;-----------------------------------------------------------------------------
1277 %macro RType_S_T_Only 0 ; no params
1278 mov rS, rS_Mask ; Mask for rS Field
1279 mov rT, rT_Mask ; Mask for rT Field
1280 and rS, r_I ; Mask orig. inst. to get rS Field
1281 and rT, r_I ; Mask orig. inst. to get rT Field
1282 shr rS, rS_Shr ; rS is now rS Index
1283 shr rT, rT_Shr ; rT is now rT Index
1284 %endmacro
1285 ;-----------------------------------------------------------------------------
1286
1287 ; Works same
1288 %define IType_S_T_Only RType_S_T_Only
1289
1290 ;-----------------------------------------------------------------------------
1291 ; Extract only rS and rD fields from the currently-executing MIPS instruction
1292 ; For instructions encoded as ???? ??ss sss? ???? dddd d??? ???? ????
1293 ;-----------------------------------------------------------------------------
1294 %macro RType_S_D_Only 0 ; no params
1295 mov rD, rD_Mask ; Mask for rD Field
1296 mov rS, rS_Mask ; Mask for rS Field
1297 and rD, r_I ; Mask orig. inst. to get rD Field
1298 and rS, r_I ; Mask orig. inst. to get rS Field
1299 shr rD, rD_Shr ; rD is now rD Index
1300 shr rS, rS_Shr ; rS is now rS Index
1301 %endmacro
1302 ;-----------------------------------------------------------------------------
1303
1304 ;-----------------------------------------------------------------------------
1305 ; Extract only rD field from the currently-executing MIPS instruction
1306 ; For instructions encoded as ???? ???? ???? ???? dddd d??? ???? ????
1307 ;-----------------------------------------------------------------------------
1308 %macro RType_D_Only 0 ; no params
1309 mov rD, rD_Mask ; Mask for rD Field
1310 and rD, r_I ; Mask orig. inst. to get rD Field
1311 shr rD, rD_Shr ; rD is now rD Index
1312 %endmacro
1313 ;-----------------------------------------------------------------------------
1314
1315 ;-----------------------------------------------------------------------------
1316 ; Extract rD, rT, Shamt fields from the currently-executing MIPS instruction
1317 ; For instructions encoded as ???? ???? ???t tttt dddd dhhh hh?? ????
1318 ;-----------------------------------------------------------------------------
1319 %macro RType_D_T_Shamt 0 ; no params
1320 mov rD, rD_Mask ; Mask for rD Field
1321 mov r_Shamt, Shamt_Mask ; Mask for Shamt Field
1322 mov rT, rT_Mask ; Mask for rT Field
1323 and rD, r_I ; Mask orig. inst. to get rD Field
1324 and r_Shamt, r_I ; Mask orig. inst. to get Shamt Field
1325 and rT, r_I ; Mask orig. inst. to get rT Field
1326 shr rD, rD_Shr ; rD is now rD Index
1327 shr r_Shamt, Shamt_Shr ; r_Shamt is now Shamt value
1328 shr rT, rT_Shr ; rT is now rT Index
1329 %endmacro
1330 ;-----------------------------------------------------------------------------
1331
1332 ;-----------------------------------------------------------------------------
1333 ; Extract rD, rT, Q fields from the currently-executing MIPS instruction
1334 ; For MFC/MTC instructions encoded as 0100 0000 ?00t tttt dddd d000 0000 0qqq
1335 ;-----------------------------------------------------------------------------
1336 %macro CPType 0 ; no params
1337 mov rD, rD_Mask ; Mask for rD Field
1338 mov r_Q, Q_Mask ; Mask for Q Field
1339 mov rT, rT_Mask ; Mask for rT Field
1340 and rD, r_I ; Mask orig. inst. to get rD Field
1341 and r_Q, r_I ; Mask orig. inst. to get Q Field
1342 and rT, r_I ; Mask orig. inst. to get rT Field
1343 shr rD, rD_Shr ; rD is now rD Index
1344 shr rT, rT_Shr ; rT is now rT Index
1345 %endmacro
1346 ;-----------------------------------------------------------------------------
1347
1348 ;-----------------------------------------------------------------------------
1349 ; Extract Imm, rS, rT fields from the currently-executing MIPS instruction
1350 ;-----------------------------------------------------------------------------
1351 %macro IType 0 ; no params
1352 mov Imm, Imm_Mask ; Mask for Imm Field; needs no shift
1353 mov rS, rS_Mask ; Mask for rS Field
1354 mov rT, rT_Mask ; Mask for rT Field
1355 and Imm, r_I ; Mask orig. inst. to get Imm Field
1356 and rS, r_I ; Mask orig. inst. to get rS Field
1357 and rT, r_I ; Mask orig. inst. to get rT Field
1358 shr rS, rS_Shr ; rS is now rS Index
1359 shr rT, rT_Shr ; rT is now rT Index
1360 %endmacro
1361 ;-----------------------------------------------------------------------------
1362
1363 ;-----------------------------------------------------------------------------
1364 ; Extract only Imm, rS fields from the currently-executing MIPS instruction
1365 ;-----------------------------------------------------------------------------
1366 %macro IType_I_S_Only 0 ; no params
1367 mov Imm, Imm_Mask ; Mask for Imm Field; needs no shift
1368 mov rS, rS_Mask ; Mask for rS Field
1369 and Imm, r_I ; Mask orig. inst. to get Imm Field
1370 and rS, r_I ; Mask orig. inst. to get rS Field
1371 shr rS, rS_Shr ; rS is now rS Index
1372 %endmacro
1373 ;-----------------------------------------------------------------------------
1374
1375 ;-----------------------------------------------------------------------------
1376 ; Extract only Imm field from the currently-executing MIPS instruction
1377 ;-----------------------------------------------------------------------------
1378 %macro IType_I_Only 0 ; no params
1379 mov Imm, Imm_Mask ; Mask for Imm Field; needs no shift
1380 and Imm, r_I ; Mask orig. inst. to get Imm Field
1381 %endmacro
1382 ;-----------------------------------------------------------------------------
1383
1384 ;-----------------------------------------------------------------------------
1385 ; Extract Imm, rT fields from the currently-executing MIPS instruction
1386 ;-----------------------------------------------------------------------------
1387 %macro IType_I_T_Only 0 ; no params
1388 mov Imm, Imm_Mask ; Mask for Imm Field; needs no shift
1389 mov rT, rT_Mask ; Mask for rT Field
1390 and Imm, r_I ; Mask orig. inst. to get Imm Field
1391 and rT, r_I ; Mask orig. inst. to get rT Field
1392 shr rT, rT_Shr ; rT is now rT Index
1393 %endmacro
1394 ;-----------------------------------------------------------------------------
1395
1396 ;-----------------------------------------------------------------------------
1397 ; Extract J field from the currently-executing MIPS instruction
1398 ; Encoding: ???? 11ii iiii iiii iiii iiii iiii iiii
1399 ;-----------------------------------------------------------------------------
1400 %macro JType 0 ; no params
1401 mov JTarg, J_Mask ; Mask for J Field; needs no shift
1402 and JTarg, r_I ; Mask orig. inst. to get J Field
1403 shl JTarg, J_Shl ; Shift the J Field to get Target Address
1404 %endmacro
1405 ;-----------------------------------------------------------------------------
1406
1407 ;-----------------------------------------------------------------------------
1408 ; Sign-Extend((16bit Address) * 4) (where 18th bit is considered 'sign')
1409 ;-----------------------------------------------------------------------------
1410 %macro SX18_4N 1 ; param is A, the address to extend
1411 shl %1, 16 ; upper 16 bits are now equal to A
1412 sar %1, 14 ; Shift back to A*4, extending sign bit.
1413 %endmacro
1414 ;-----------------------------------------------------------------------------
1415
1416 ;-----------------------------------------------------------------------------
1417 ; Sign-Extend(16bit Address) (where 16th bit is considered 'sign')
1418 ;-----------------------------------------------------------------------------
1419 %macro SX16 1 ; param is A, the address to extend
1420 shl %1, 16 ; upper 16 bits are now equal to A
1421 sar %1, 16 ; Shift back to A, extending sign bit.
1422 %endmacro
1423 ;-----------------------------------------------------------------------------
1424
1425 ;-----------------------------------------------------------------------------
1426 ; Denote privileged (permitted in Kernel-Mode strictly) instructions.
1427 ;-----------------------------------------------------------------------------
1428 %macro PRIVILEGED 0
1429 bt CP0_Status, CP0St_UM ; CF := CP0St_UM Flag
1430 jnc %%proceed ; If UM = 0: Kernel Mode, proceed.
1431 test CP0_Status, (1 << CP0St_EXL) | (1 << CP0St_ERL) ; EXL or ERL
1432 jnz %%proceed ; If EXL && ERL: Kernel Mode, proceed.
1433 ;; We are NOT in kernel mode, but trying to execute a privileged inst:
1434 SetEXC EXC_RI ; Set the 'Reserved Instr.' Exception.
1435 jmp _Handle_Exception ; Go straight to exception handler.
1436 %%proceed ; We're in Kernel Mode, so proceed with the privileged instruction.
1437 %endmacro
1438 ;-----------------------------------------------------------------------------
1439
1440 ;-----------------------------------------------------------------------------
1441 ; Store the significant 32 bits of locative
1442 ;-----------------------------------------------------------------------------
1443 %macro A32 1 ; %1: locative
1444 dd %1
1445 %endmacro
1446 ;-----------------------------------------------------------------------------
-
+ E55DA0353DA36AFDBE061D4AE3AAAF02C58D2CA7189786C7D13684AAF4BF39D428EE4787C6B858F467513B35F14272FAC53AF48CB5864AF19A03DEF98A0D4622
m/irq.asm
(0 . 0)(1 . 70)
1451 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1452 ;; ;;
1453 ;; This file is part of 'M', a MIPS system emulator. ;;
1454 ;; ;;
1455 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1456 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1457 ;; ;;
1458 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1459 ;; distribute this software ; Should you use this software for any purpose, ;;
1460 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1461 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1462 ;; continue doing so for the indefinite future. In any case, please ;;
1463 ;; always : read and understand any software ; verify any PGP signatures ;;
1464 ;; that you use - for any purpose. ;;
1465 ;; ;;
1466 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1467 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1468
1469 ;-----------------------------------------------------------------------------
1470 ;; State
1471 ;-----------------------------------------------------------------------------
1472 section .bss
1473 SlaveIRQ resd 1 ; External Interrupt from Slaves
1474 ;-----------------------------------------------------------------------------
1475
1476 section .text
1477
1478 ;-----------------------------------------------------------------------------
1479 ; SetIRQ : Trigger External Interrupt ( Parameter: constant IRQ # )
1480 ;-----------------------------------------------------------------------------
1481 %macro SetIRQ 1 ; param is the IRQ #
1482 bts CP0_Cause, (CP0Cau_IRQ_Bottom + %1)
1483 %endmacro
1484 ;-----------------------------------------------------------------------------
1485
1486 ;-----------------------------------------------------------------------------
1487 ; ClrIRQ : Clear External Interrupt ( Parameter: constant IRQ # )
1488 ;-----------------------------------------------------------------------------
1489 %macro ClrIRQ 1 ; param is the IRQ #
1490 btr CP0_Cause, (CP0Cau_IRQ_Bottom + %1)
1491 %endmacro
1492 ;-----------------------------------------------------------------------------
1493
1494 ;-----------------------------------------------------------------------------
1495 ; Built-In Iron IRQs:
1496 ;-----------------------------------------------------------------------------
1497 %define TIMER_IRQ 7 ; MIPS Timer (trigger when CP0_Count==CP0_Compare)
1498 ;-----------------------------------------------------------------------------
1499
1500 ;-----------------------------------------------------------------------------
1501 ; IRQ from Slave:
1502 ;; TODO: locking and wait/sleep
1503 ;-----------------------------------------------------------------------------
1504 %macro SetSlaveIRQ 1
1505 bts dword [SlaveIRQ], (CP0Cau_IRQ_Bottom + %1)
1506 %endmacro
1507 ;-----------------------------------------------------------------------------
1508
1509 ;-----------------------------------------------------------------------------
1510 ; Poll for any Slave IRQ:
1511 ;-----------------------------------------------------------------------------
1512 %macro GetSlaveIRQ 0
1513 mov eax, [SlaveIRQ] ; Get the Slave IRQ shadow register
1514 test eax, eax ; Is it zero?
1515 jz %%skip ; If was zero, skip;
1516 mov dword [SlaveIRQ], 0 ; Else, 1) Zero shadow register
1517 or CP0_Cause, eax ; 2) OR it into CP0_Cause.
1518 %%skip:
1519 %endmacro
1520 ;-----------------------------------------------------------------------------
-
+ E75680EEE6B4D6DAB5E13FD02DB2A86702136633846D4E9D9CA17FFAAE25CE6C1D0D138DB69081802520D9B418B7027A8150271E15E954971BA44D2506F70AD1
m/knobs.asm
(0 . 0)(1 . 60)
1525 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1526 ;; ;;
1527 ;; This file is part of 'M', a MIPS system emulator. ;;
1528 ;; ;;
1529 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1530 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1531 ;; ;;
1532 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1533 ;; distribute this software ; Should you use this software for any purpose, ;;
1534 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1535 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1536 ;; continue doing so for the indefinite future. In any case, please ;;
1537 ;; always : read and understand any software ; verify any PGP signatures ;;
1538 ;; that you use - for any purpose. ;;
1539 ;; ;;
1540 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1541 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1542
1543 ;-----------------------------------------------------------------------------
1544 ; Endianism. LITTLE_ENDIAN -- 'little' ; otherwise 'big'
1545 ;-----------------------------------------------------------------------------
1546 ; %define LITTLE_ENDIAN 1
1547 ;-----------------------------------------------------------------------------
1548
1549 ;-----------------------------------------------------------------------------
1550 ; Alignment Grain
1551 ;-----------------------------------------------------------------------------
1552 %define GRAIN 32
1553 ;-----------------------------------------------------------------------------
1554
1555 ;-----------------------------------------------------------------------------
1556 ; Memory Size (MB)
1557 ;-----------------------------------------------------------------------------
1558 %define RAM_SIZE_MB 1040
1559 ;-----------------------------------------------------------------------------
1560
1561 ;-----------------------------------------------------------------------------
1562 ; Start and End of MMIO Peripheral Space
1563 ;-----------------------------------------------------------------------------
1564 %define MMIO_BASE 0x14000000 ;; Bottom of Memory-Mapped Dev. Bus
1565 %define MMIO_TOP 0x1400FFFF ;; Top of Memory-Mapped Dev. Bus
1566 ;-----------------------------------------------------------------------------
1567
1568 ;-----------------------------------------------------------------------------
1569 ; Size of Slave thread stacks
1570 ;-----------------------------------------------------------------------------
1571 %define SLAVE_STACK_SIZE (4 * 1024) ;; 4kB
1572 ;-----------------------------------------------------------------------------
1573
1574 ;-----------------------------------------------------------------------------
1575 ; Timer Slave Frequency (nsec)
1576 ;-----------------------------------------------------------------------------
1577 %define TIMER_SLAVE_PERIOD 10000000 ; for 100Hz
1578 ;-----------------------------------------------------------------------------
1579
1580 ;-----------------------------------------------------------------------------
1581 ; Command Line Argument Count
1582 ;-----------------------------------------------------------------------------
1583 %define CMDLINE_ARG_COUNT 1
1584 ;-----------------------------------------------------------------------------
-
+ 7B3DB846A77DD59146B68F83C06D01C6BE491C8E5A78BA0B1D5EA49BA93020AEA4B1080D287566C6F5FCE1436657DDDC54811FE0BED35C918C2165F630E9EC88
m/log.asm
(0 . 0)(1 . 39)
1589 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1590 ;; ;;
1591 ;; This file is part of 'M', a MIPS system emulator. ;;
1592 ;; ;;
1593 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1594 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1595 ;; ;;
1596 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1597 ;; distribute this software ; Should you use this software for any purpose, ;;
1598 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1599 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1600 ;; continue doing so for the indefinite future. In any case, please ;;
1601 ;; always : read and understand any software ; verify any PGP signatures ;;
1602 ;; that you use - for any purpose. ;;
1603 ;; ;;
1604 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1605 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1606
1607 ;-----------------------------------------------------------------------------
1608 %macro ACHTUNG 1
1609 [section .rodata]
1610 %%text:
1611 dd %%endstr - %%str ; Store 32-bit length of text string
1612 %%str: db %1, 10 ; Store the text string itself + newline
1613 %%endstr:
1614 __SECT__
1615 push rdx
1616 mov rdx, %%text
1617 call _Print_Text_STDERR
1618 pop rdx
1619 %endmacro
1620 ;-----------------------------------------------------------------------------
1621
1622 ;-----------------------------------------------------------------------------
1623 %macro EGGOG 1
1624 ACHTUNG %1
1625 jmp _exit
1626 %endmacro;
1627 ;-----------------------------------------------------------------------------
-
+ CA9D23D0ADA3927D70455EC847E8C92ECF88E4B8A4295F07D89155D8322F7A096C47895C506C451F9D1F12F58BC4FBEA4D01D76E673755D76A93ED81206554D4
m/m.asm
(0 . 0)(1 . 156)
1632 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1633 ;; 'M', a MIPS system emulator. ;;
1634 ;; Version: 300K. ;;
1635 ;; ;;
1636 ;; Will run lightly-modified Linux kernels with full isolation vs. host. ;;
1637 ;; To keep things simple, dynamic recompilation a la Bellard's is NOT USED! ;;
1638 ;; ;;
1639 ;; 'M' aims to 'fit-in-head'. As such, a reasonably complete description ;;
1640 ;; of the emulated machine architecture is included in the comments. ;;
1641 ;; ;;
1642 ;; Dependencies/Libraries required : NONE!!! ;;
1643 ;; Where Runs: Any AMD64 linux. ;;
1644 ;; ;;
1645 ;; To build: ;;
1646 ;; 'make' (needs 'gnumake') ;;
1647 ;; or: ;;
1648 ;; (1) yasm -f elf64 -g null m.asm ;;
1649 ;; (2) ld m.o -o m ;;
1650 ;; (3) strip m ;;
1651 ;; At the time of writing, yields a <13kB ELF. ;;
1652 ;; ;;
1653 ;; To run: ;;
1654 ;; ./bin/m kernel.bin ;;
1655 ;; ;;
1656 ;; Note: currently the only means to exit (other than 'kill -9') is to ;;
1657 ;; shut down the guest OS (In 'busybox' -- 'poweroff' command.) ;;
1658 ;; ;;
1659 ;; Devices Currently Emulated (see 'devices' dir) : ;;
1660 ;; MIPS Timer, 100Hz Timer, UART Console, Realtime Clock, Power Switch. ;;
1661 ;; ;;
1662 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1663 ;; ;;
1664 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1665 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1666 ;; ;;
1667 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1668 ;; distribute this software ; Should you use this software for any purpose, ;;
1669 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1670 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1671 ;; continue doing so for the indefinite future. In any case, please ;;
1672 ;; always : read and understand any software ; verify any PGP signatures ;;
1673 ;; that you use - for any purpose. ;;
1674 ;; ;;
1675 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1676 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1677
1678 ;-----------------------------------------------------------------------------
1679 %include "knobs.asm" ; User-adjustable Knobs
1680 %include "log.asm" ; Eggogology and Warning reporting
1681 %include "os/linux.asm" ; Linux invariants and threading knob
1682 %include "os/linux_io.asm" ; Linux I/O routines
1683 %include "flags.asm" ; Emulator State Flags
1684 %include "mips.asm" ; MIPS CPU Invariants
1685 %include "i_decode.asm" ; MIPS Instruction Decoding
1686 %include "cpustate.asm" ; MIPS CPU State
1687 %include "mips_exc.asm" ; MIPS Exception Handler
1688 %include "irq.asm" ; MIPS Interrupts
1689 %include "ram.asm" ; Memory
1690 %include "bus.asm" ; Memory-Mapped Devices
1691 %include "mips_cpu.asm" ; MIPS CPU Cycle Execution
1692 %include "mipsinst/i_instrs.asm" ; I-Type MIPS Instructions
1693 %include "mipsinst/r_instrs.asm" ; R-Type MIPS Instructions
1694 %include "mipsinst/b_instrs.asm" ; B-Type MIPS Instructions
1695 %include "mipsinst/m_instrs.asm" ; M-Type MIPS Instructions
1696 %include "shutdown.asm" ; Termination Cleanup
1697 ;-----------------------------------------------------------------------------
1698
1699 ;-----------------------------------------------------------------------------
1700 ;; State
1701 ;-----------------------------------------------------------------------------
1702 section .bss
1703 arg0 resb 8 ; First Command Line Argument
1704 fd resb 8 ; FD of file containing kernel image
1705 ;-----------------------------------------------------------------------------
1706
1707 ;; TODO: 1) Make RAM size adjustable. 2) Eat kernels in ELF form ?
1708 ;; 3) Move ALL os-istic calls into os/linux.asm ?
1709 ;; 4) Right now we use 100% of host CPU. Need sleep in wait and futex.
1710 ;; 5) Need devices! particularly 'disk' and 'NIC'. (And FG...!)
1711 ;; 6) Bring UART0 console out as TCP-able?
1712 ;; 7) 'Suspend/Resume', out-of-band debuggisms?
1713 ;; 8) Tests!!! Particularly, per-instruction test cases! Can you write?
1714
1715 ;-----------------------------------------------------------------------------
1716 ; Start of Program.
1717 ;-----------------------------------------------------------------------------
1718 section .text
1719 global _start
1720 _start:
1721 ;; Get argc (# of command line arguments) :
1722 mov rax, [rsp]
1723 cmp rax, CMDLINE_ARG_COUNT + 1 ; The required arg. count
1724 je ._run
1725 ;; Not correct number of args? then print usage and exit:
1726 ._usage:
1727 EGGOG "Usage: ./M KERNEL"
1728 ._run:
1729 ;; Test if SSE2 instructions are available on this machine:
1730 mov eax, 1
1731 cpuid
1732 test edx, 0x4000000
1733 jnz ._xmm_ok
1734 EGGOG "Needs SSE2!"
1735 ._xmm_ok:
1736
1737 ;; Get 1st cmdline arg (path)
1738 mov rdi, [rsp + 16]
1739 mov [arg0], rdi
1740
1741 ;; fd = open(path, O_RDONLY)
1742 mov rax, SYS_OPEN
1743 mov rdi, [arg0] ; first arg
1744 mov rsi, 0 ; O_RDONLY
1745 syscall
1746 test rax, rax ; see if eggog
1747 jns ._ok ; if worked
1748 EGGOG "Could not read kernel from disk!"
1749 ._ok:
1750 mov [fd], rax ; else, save fd
1751
1752 ;; Mbytes = fstat(fd).st_size (footprint of initial image)
1753 mov rax, SYS_FSTAT
1754 sub rsp, statbuf.size ; make scratch
1755 mov rsi, rsp
1756 mov rdi, [fd]
1757 syscall
1758 mov rax, [rsp + statbuf.st_size]
1759 mov [Mbytes], rax
1760 add rsi, statbuf.size ; unmake scratch
1761
1762 ;; RAM size
1763 mov qword [RAMbytes], RAM_SIZE_MB * (1024 * 1024)
1764 call _ram_allocate
1765 mov [M], rax
1766
1767 ;; Load the given kernel into bottom of sim RAM:
1768 mov rax, SYS_READ
1769 mov rdi, [fd] ; fd of memory snapshot
1770 mov rsi, [M] ; where to put
1771 mov rdx, [Mbytes] ; read whole snapshot into bottom of sim ram
1772 syscall
1773
1774 ;; close(fd)
1775 mov rax, SYS_CLOSE
1776 mov rdi, [fd]
1777 syscall
1778
1779 ;; Initialize all MMIO Devices (and start all slave threads) :
1780 call _Phys_Devices_Initialize
1781
1782 ;-----------------------------------------------------------------------------
1783 _Master_Thread:
1784 call _ram_init ; Initialize RAM
1785 call _cpu_reset ; Reset the MIPS CPU
1786 jmp _cycle ; Start the engine
1787 ;-----------------------------------------------------------------------------
-
+ F82EA8FEBCEB149C589262C1387C2A99D641219DAC217DE1BA1E3E99ED8B815B5FE4F6B68128CB55FEFED5BD41B4D764C802B6EBCE34BD4580769027CA001CD7
m/mips.asm
(0 . 0)(1 . 117)
1792 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1793 ;; ;;
1794 ;; This file is part of 'M', a MIPS system emulator. ;;
1795 ;; ;;
1796 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1797 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1798 ;; ;;
1799 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1800 ;; distribute this software ; Should you use this software for any purpose, ;;
1801 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1802 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1803 ;; continue doing so for the indefinite future. In any case, please ;;
1804 ;; always : read and understand any software ; verify any PGP signatures ;;
1805 ;; that you use - for any purpose. ;;
1806 ;; ;;
1807 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1808 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1809
1810 ;-----------------------------------------------------------------------------
1811 ; Value of Program Counter (PC) on Warmup
1812 ;-----------------------------------------------------------------------------
1813 %define INIT_PC 0xBFC00000 ; Per traditional MIPS standard.
1814 ;-----------------------------------------------------------------------------
1815
1816 ;-----------------------------------------------------------------------------
1817 ; # of TLB entries. Could have more; but would have to change not only here.
1818 ;-----------------------------------------------------------------------------
1819 %define TLB_ENTRIES_COUNT 16 ; in principle could have more.
1820 ;-----------------------------------------------------------------------------
1821
1822 ;-----------------------------------------------------------------------------
1823 ; MIPS Exceptions Codes (See CP0_Cause Flags re: where they sit)
1824 ;-----------------------------------------------------------------------------
1825 %define EXC_Int 0 ; Interrupt
1826 %define EXC_Mod 1 ; TLB modification exception
1827 %define EXC_TLBL 2 ; TLB exception (load or instruction fetch)
1828 %define EXC_TLBS 3 ; TLB exception (store)
1829 %define EXC_AdEL 4 ; Address error exception (load or instruction fetch)
1830 %define EXC_AdES 5 ; Address error exception (store)
1831 %define EXC_IBE 6 ; Bus error exception (instruction fetch)
1832 %define EXC_DBE 7 ; Bus error exception (data reference: load or store)
1833 %define EXC_SYS 8 ; Syscall exception
1834 %define EXC_BP 9 ; Breakpoint exception
1835 %define EXC_RI 10 ; Reserved instruction exception
1836 %define EXC_CpU 11 ; Coprocessor Unusable exception
1837 %define EXC_Ov 12 ; Arithmetic Overflow exception
1838 %define EXC_Tr 13 ; Trap exception
1839 %define EXC_Watch 23 ; Reference to WatchHi/WatchLo address
1840 %define EXC_MCheck 24 ; Machine check
1841 ;-----------------------------------------------------------------------------
1842
1843 ;-----------------------------------------------------------------------------
1844 ; MIPS CP0_Cause Register
1845 ;-----------------------------------------------------------------------------
1846 ; 11111111111111110000000000000000 EEEEE - Exception Code; IIIIIIII - IRQ;
1847 ; FEDCBA9876543210FEDCBA9876543210 IV - Indicates whether an interrupt
1848 ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ exception uses the general exception
1849 ; B0CC0000IW000000IIIIIIII0EEEEE00 vector or a special interrupt vector:
1850 ; D EE VP 76543210 0: General exception vector (0x180)
1851 ; 1: Special interrupt vector (0x200)
1852 ; BD - Indicates whether last exception taken occurred in a branch delay slot.
1853 ; 0: Not in delay slot; 1: In delay slot.
1854 ; BD bit is not updated on a new exception if the EXL bit is set.
1855 ; IRQ0, IRQ1 -- 'software IRQ'; IRQ2..IRQ7 -- iron IRQ.
1856 ; MIPS Timer (powered by CP0_Count and CP0_Compare) is perma-soldered to IRQ7.
1857 ;-----------------------------------------------------------------------------
1858 %define CP0Cau_IRQ_Bottom 8 ; Index of bit in CP0_Cause where IRQ # lives
1859 %define CP0Cau_IV 23 ; Whether exception uses general or special vect
1860 %define CP0Cau_BD 31 ; Whether exception occurred in branch delay slt
1861 ;-----------------------------------------------------------------------------
1862
1863 ;-----------------------------------------------------------------------------
1864 ; MIPS CP0_Status Register
1865 ;-----------------------------------------------------------------------------
1866 %define CP0St_CU3 31 ; Coprocessor Access CU3 (unused)
1867 %define CP0St_CU2 30 ; Coprocessor Access CU2 (unused)
1868 %define CP0St_CU1 29 ; Coprocessor Access CU1 (unused)
1869 %define CP0St_CU0 28 ; Coprocessor Access CU0 (unused)
1870 %define CP0St_RP 27 ; Reduced Power Mode (unused)
1871 %define CP0St_FR 26 ; Floating Point Reg Mode -- Unused on 32-bit MIPS
1872 %define CP0St_RE 25 ; Reverse-Endianism (0: user, 1: flipped) - unused
1873 %define CP0St_MX 24 ; Unused on 32-bit MIPS
1874 %define CP0St_PX 23 ; Unused on 32-bit MIPS
1875 %define CP0St_BEV 22 ; BEV (0: Normal Exception Vector, 1: Bootstrap)
1876 %define CP0St_TS 21 ; TLB 'multi-match' shutdown (unused)
1877 %define CP0St_SR 20 ; Soft Reset (0: not soft, 1: soft)
1878 %define CP0St_NMI 19 ; NMI (unused)
1879 %define CP0St_IM 8 ; Start of Interrupt Mask (0: IRQ OFF, 1: IRQ ON)
1880 %define CP0St_KX 7 ; Unused on 32-bit MIPS
1881 %define CP0St_SX 6 ; Unused on 32-bit MIPS
1882 %define CP0St_UX 5 ; Unused on 32-bit MIPS
1883 %define CP0St_UM 4 ; User Mode (0: Kernel Mode, 1: User Mode)
1884 %define CP0St_KSU 3 ; Unused
1885 %define CP0St_ERL 2 ; Error Level (0: Normal, 1: Error)
1886 %define CP0St_EXL 1 ; Exception Level (0: Normal, 1: Kernel)
1887 %define CP0St_IE 0 ; Interrupt Enable
1888 ;-----------------------------------------------------------------------------
1889
1890 ;-----------------------------------------------------------------------------
1891 ; MIPS TLB Entry.
1892 ; We don't use C0 and C1 anywhere! and so we can put all of it in 32bits:
1893 ;-----------------------------------------------------------------------------
1894 ; 11111111111111110000000000000000
1895 ; FEDCBA9876543210FEDCBA9876543210
1896 ; --------------------------------
1897 ; GVVDDAAAAAAAAVVVVVVVVVVVVVVVVVVV
1898 ; |1010| ASID || VPN2 |
1899 ;-----------------------------------------------------------------------------
1900 %define TLB_VPN2_Mask 0x7FFFF ; 19 bits
1901 %define TLB_ASID_Mask 0xFF ; 8 bits
1902 %define TLB_ASID_Shift 19 ; sits after VPN2 Mask
1903 %define TLB_D0 27 ; 27th bit
1904 %define TLB_D1 28 ; 28th bit
1905 %define TLB_V0 29 ; 29th bit
1906 %define TLB_V1 30 ; 30th bit
1907 %define TLB_G 31 ; 31st bit (last)
1908 ;-----------------------------------------------------------------------------
-
+ 93767FBF28AC3CA8A8D7CEA92C2295D7F4A041C9B67B003EDC7CA1A32AE624B423F8F33E5D099403A9E68E794F0F5D90F4F3F2A12E8D3CEE4FCAFB12E7502684
m/mips_cpu.asm
(0 . 0)(1 . 113)
1913 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1914 ;; ;;
1915 ;; This file is part of 'M', a MIPS system emulator. ;;
1916 ;; ;;
1917 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
1918 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
1919 ;; ;;
1920 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
1921 ;; distribute this software ; Should you use this software for any purpose, ;;
1922 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
1923 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
1924 ;; continue doing so for the indefinite future. In any case, please ;;
1925 ;; always : read and understand any software ; verify any PGP signatures ;;
1926 ;; that you use - for any purpose. ;;
1927 ;; ;;
1928 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
1929 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1930
1931 section .text
1932
1933 ;-----------------------------------------------------------------------------
1934 ; Dispatch via rax, given index Register, and given Table (of 32-bit offsets)
1935 ;-----------------------------------------------------------------------------
1936 %macro JTABLE 2 ; %1 : index register, %2 : table offset
1937 mov eax, dword [%2 + 4 * %1]
1938 jmp rax
1939 %endmacro
1940 ;-----------------------------------------------------------------------------
1941
1942 ;----------------------------
1943 ; Start of MIPS CPU Cycle : |
1944 ;-----------------------------------------------------------------------------
1945 _wait_cycle:
1946 _cycle:
1947 inc CP0_Count ; Timer: CP0_Count := CP0_Count + 1
1948
1949 ;; Timer Interrupt
1950 cmp CP0_Count, CP0_Compare ; Has timer reached limit?
1951 jne _cycle_no_mips_timer ; If not, do not invoke interrupt
1952 SetIRQ TIMER_IRQ ; Timer reached limit, invoke timer IRQ
1953
1954 _cycle_no_mips_timer:
1955
1956 ;; Test if Interrupts are Disabled:
1957 bt CP0_Status, CP0St_IE ; CF := CP0St_IE
1958 jnc _cycle_no_irq ; If 0, IRQs are disabled, go to no_irq
1959 test CP0_Status, (1 << CP0St_ERL) | (1 << CP0St_EXL) ; If ERL/EXL:
1960 jnz _cycle_no_irq ; ... then also interrupts are disabled
1961
1962 GetSlaveIRQ ; See if slave threw interrupt
1963
1964 ;; Interrupts are Enabled; handle any pending Interrupt:
1965 mov eax, 0xFC00 ; ( 0xFC00 &
1966 and eax, CP0_Cause ; CP0_Cause &
1967 and eax, CP0_Status ; CP0_Status )
1968 jz _cycle_no_irq ; == 0 ? Then no pending IRQ, go to no_irq.
1969
1970 ;; If here, there is a pending interrupt, service it:
1971 _cycle_irq_handler:
1972
1973 Flg_Off Waiting ; Clear Waiting Flag
1974 SetEXC EXC_Int ; Set the EXC_Int Exception Code
1975
1976 ;; Copy InDelaySlot Flag to RunningDelaySlot Flag:
1977 Flg_Cpy RunningDelaySlot, InDelaySlot
1978
1979 jmp _Handle_Exception ; Handle exception and end cycle.
1980
1981 _cycle_no_irq: ; If ints disabled or none pending
1982
1983 Flg_Get Waiting ; CF := Waiting Flag
1984 jc _wait_cycle ; If Waiting, start next cycle, else:
1985
1986 ;; Copy InDelaySlot Flag to RunningDelaySlot Flag:
1987 Flg_Cpy RunningDelaySlot, InDelaySlot
1988
1989 ;; Fetch the instruction to execute:
1990 mov eax, PC ; vAddr := PC
1991 call _Virt_Read_Word ; EAX := MEM[Virt2Phys(PC)]
1992 mov r_I, eax ; Store fetched instruction
1993
1994 ;; Dispatch the current instruction:
1995 mov eax, r_I ; Get the original instruction :
1996
1997 ;; 'Accelerated NOPs'
1998 test eax, eax ; Is the current instruction null?
1999 jnz _not_nop ; ... if so, skip dispatch entirely!
2000 jmp _end_cycle ; go to tail of this cycle
2001 _not_nop: ; If not a NOP:
2002
2003 shr eax, 26 ; Get I-field (upper 6 bits of instr) ;
2004 JTABLE eax, _I_Table ; Dispatch on I-field via I-Table.
2005 ;;; Instruction executes, after which goes to _end_cycle
2006 ;-----------------------------------------------------------------------------
2007
2008 ;---------------------------------
2009 ; Tail End of a MIPS CPU Cycle : |
2010 ;-----------------------------------------------------------------------------
2011 _end_cycle:
2012 Flg_GOF RunningDelaySlot ; Were we running the delay slot?
2013 jnc _end_cycle_was_not_in_delay_slot ; if not, skip, else:
2014 ;; We WERE running in the delay slot:
2015 _end_cycle_was_in_delay_slot: ; If we were running the delay slot:
2016 mov PC, nPC ; PC := nPC
2017 Flg_Off InDelaySlot ; Clear the InDelaySlot Flag
2018 jmp _cycle ; Go to next cycle without advancing PC
2019 _end_cycle_was_not_in_delay_slot: ; If we were NOT running the delay slot:
2020 add PC, 0x4 ; PC := PC + 4
2021 ;; Test for Shutdown Condition:
2022 Flg_Get Shutdown ; CF := Shutdown Flag
2023 jc _shutdown ; ... if CF, then shut down.
2024 jmp _cycle ; ... otherwise, go to next cycle.
2025 ;-----------------------------------------------------------------------------
-
+ FD686B4ADBDB138A08F6B8F95620FD0533B2BD68C5B5056D24100F28B552CB6E7AF74B32BFD739F029E065D257F456024D223073DA3F0F8168E6D98F75BE053D
m/mips_exc.asm
(0 . 0)(1 . 92)
2030 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2031 ;; ;;
2032 ;; This file is part of 'M', a MIPS system emulator. ;;
2033 ;; ;;
2034 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
2035 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
2036 ;; ;;
2037 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
2038 ;; distribute this software ; Should you use this software for any purpose, ;;
2039 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
2040 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
2041 ;; continue doing so for the indefinite future. In any case, please ;;
2042 ;; always : read and understand any software ; verify any PGP signatures ;;
2043 ;; that you use - for any purpose. ;;
2044 ;; ;;
2045 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
2046 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2047
2048 section .text
2049
2050 ;-----------------------------------------------------------------------------
2051 ; Get the current Exception Code, write to the specified destination
2052 ;-----------------------------------------------------------------------------
2053 %macro GetEXC 1 ; param is destination to write the exception code
2054 mov %1, CP0_Cause ; Dest := CP0_Cause
2055 shr %1, 2 ; Dest := Dest >> 2
2056 and %1, 0x1F ; Dest := Dest & 0x1F
2057 %endmacro
2058 ;-----------------------------------------------------------------------------
2059
2060 ;-----------------------------------------------------------------------------
2061 ; Set the current Exception Code from the given constant
2062 ;-----------------------------------------------------------------------------
2063 %macro SetEXC 1 ; param is the exception code to set
2064 and CP0_Cause, ~(0x1F << 2) ; Clear the current Exception Code
2065 or CP0_Cause, (%1 & 0x1F) << 2 ; set the new one
2066 %endmacro
2067 ;-----------------------------------------------------------------------------
2068
2069 ;------------------------------
2070 ; Exception (and IRQ) Handler |
2071 ;-----------------------------------------------------------------------------
2072 _Handle_Exception:
2073 Flg_Off InDelaySlot ; Clear the InDelaySlot Flag
2074 bt CP0_Status, CP0St_EXL ; CF := EXL
2075 jc _H_Exc_Off_Is_180 ; If EXL is 1, Offset := 0x180; else:
2076 ;; EXL is 0:
2077 mov Sr(CP0_Epc), PC ; CP0_Epc := PC
2078 Flg_Get RunningDelaySlot ; Are we running the delay slot?
2079 jnc _H_Exc_Not_R_Delay ; If yes, then skip, else:
2080 _H_Exc_R_Delay: ; We ARE running the delay slot:
2081 sub Sr(CP0_Epc), 0x4 ; CP0_Epc := CP0_Epc - 0x4
2082 bts CP0_Cause, CP0Cau_BD ; Set BD Flag in CP0_Cause
2083 jmp _H_Exc_Test_TLB ; Proceed to test for TLBism
2084 _H_Exc_Not_R_Delay: ; We are NOT running the delay slot:
2085 btr CP0_Cause, CP0Cau_BD ; Clear BD Flag in CP0_Cause
2086 _H_Exc_Test_TLB:
2087 ;; Test whether this was a TLB Exception:
2088 GetEXC eax ; EAX := the current exception code
2089 cmp eax, EXC_TLBL ; was it EXC_TLBL ?
2090 je __H_Exc_Was_TLB ; ... if yes, go to H_Exc_Was_TLB
2091 cmp eax, EXC_TLBS ; was it EXC_TLBS ?
2092 je __H_Exc_Was_TLB ; ... if yes, go to H_Exc_Was_TLB
2093 ;; This was NOT a TLB Exception:
2094 cmp eax, EXC_Int ; was code EXC_Int ?
2095 jne _H_Exc_Off_Is_180 ; if not, Offset := 0x180
2096 bt CP0_Cause, CP0Cau_IV ; Was CP0_Cause bit 23 (IV) zero?
2097 jnc _H_Exc_Off_Is_180 ; if was zero, Offset := 0x180
2098 ;; If CP0_Cause bit 23 != 0: Offset := 0x200
2099 mov eax, 0x200 ; Offset := 0x200
2100 jmp _H_Exc_Have_Offset ; Go to H_Exc_Have_Offset
2101 __H_Exc_Was_TLB: ; This WAS a TLB Exception:
2102 Flg_Get ExcWasTLBNoMatch ; CF := 'TLB No Match'
2103 ;; TODO: in 'cmips', this case was reversed? why?
2104 ;; For now, we'll do likewise:
2105 jnc _H_Exc_Off_Is_180 ; ... if 0, Offset := 0x180
2106 ;; Else: Offset := 0x0
2107 xor eax, eax ; Clear EAX (Offset := 0)
2108 jmp _H_Exc_Have_Offset ; Finish up
2109 _H_Exc_Off_Is_180: ; Offset := 0x180
2110 mov eax, 0x180 ; Set the Offset
2111 _H_Exc_Have_Offset: ; We finished calculating the Offset:
2112 bts CP0_Status, CP0St_EXL ; Set the EXL Flag
2113 mov PC, eax ; PC := Offset (eax)
2114 mov eax, 0x80000000 ; Base that will be used if BEV=0
2115 mov ebx, 0xBFC00200 ; Base that will be used if BEV=1
2116 bt CP0_Status, CP0St_BEV ; CF := the BEV Flag
2117 cmovc eax, ebx ; If CF = 1, use the BEV=1 Base
2118 add PC, eax ; PC := PC + Base
2119 ;; Done handling exception
2120 jmp _cycle ; Start next cycle.
2121 ;-----------------------------------------------------------------------------
-
+ 0049B58D97622DD2210F1547D96A7A69606C9EF7FD46349B1B16DB6E5A6F686D84296BCB2CCEEA2240A5BD82E46D1AC5A03C6C131F14906FC0E173C1A9A46B58
m/mipsinst/b_instrs.asm
(0 . 0)(1 . 225)
2126 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2127 ;; ;;
2128 ;; This file is part of 'M', a MIPS system emulator. ;;
2129 ;; ;;
2130 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
2131 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
2132 ;; ;;
2133 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
2134 ;; distribute this software ; Should you use this software for any purpose, ;;
2135 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
2136 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
2137 ;; continue doing so for the indefinite future. In any case, please ;;
2138 ;; always : read and understand any software ; verify any PGP signatures ;;
2139 ;; that you use - for any purpose. ;;
2140 ;; ;;
2141 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
2142 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2143
2144 ;-----------------------------------------------------------------------------
2145 section .rodata
2146 align GRAIN, db 0x90
2147 _B_Table:
2148 A32 _b_bltz ; 0x00 : bltz (000001?????00000????????????????)
2149 A32 _b_bgez ; 0x01 : bgez (000001?????00001????????????????)
2150 A32 _b_bltzl ; 0x02 : bltzl (000001?????00010????????????????)
2151 A32 _b_bgezl ; 0x03 : bgezl (000001?????00011????????????????)
2152 A32 _bad ; 0x04 : UNDEFINED
2153 A32 _bad ; 0x05 : UNDEFINED
2154 A32 _bad ; 0x06 : UNDEFINED
2155 A32 _bad ; 0x07 : UNDEFINED
2156 A32 _bad ; 0x08 : UNDEFINED
2157 A32 _bad ; 0x09 : UNDEFINED
2158 A32 _bad ; 0x0a : UNDEFINED
2159 A32 _bad ; 0x0b : UNDEFINED
2160 A32 _bad ; 0x0c : UNDEFINED
2161 A32 _bad ; 0x0d : UNDEFINED
2162 A32 _bad ; 0x0e : UNDEFINED
2163 A32 _bad ; 0x0f : UNDEFINED
2164 A32 _b_bltzal ; 0x10 : bltzal (000001????x10000????????????????)
2165 A32 _b_bgezal ; 0x11 : bgezal (000001????x10001????????????????)
2166 A32 _bad ; 0x12 : UNDEFINED
2167 A32 _bad ; 0x13 : UNDEFINED
2168 A32 _bad ; 0x14 : UNDEFINED
2169 A32 _bad ; 0x15 : UNDEFINED
2170 A32 _bad ; 0x16 : UNDEFINED
2171 A32 _bad ; 0x17 : UNDEFINED
2172 A32 _bad ; 0x18 : UNDEFINED
2173 A32 _bad ; 0x19 : UNDEFINED
2174 A32 _bad ; 0x1a : UNDEFINED
2175 A32 _bad ; 0x1b : UNDEFINED
2176 A32 _bad ; 0x1c : UNDEFINED
2177 A32 _bad ; 0x1d : UNDEFINED
2178 A32 _bad ; 0x1e : UNDEFINED
2179 A32 _bad ; 0x1f : UNDEFINED
2180 ;-----------------------------------------------------------------------------
2181
2182 section .text
2183
2184 ;-----------------------------------------------------------------------------
2185 ; B-Type Instructions :
2186 ;-----------------------------------------------------------------------------
2187
2188 ;-----------------------------------------------------------------------------
2189 ; BLTZ -- Branch on less than zero.
2190 ; Branches if the register is less than zero
2191 ; Operation: if $s < 0 advance_pc(offset << 2)); else advance_pc(4);
2192 ; Syntax: bltz $s, offset
2193 ; Encoding: 0000 01ss sss0 0000 iiii iiii iiii iiii
2194 ;-----------------------------------------------------------------------------
2195 align GRAIN, db 0x90
2196 _b_bltz:
2197 IType_I_S_Only ; load rS and Imm Fields
2198 mov nPC, PC ; nPC := PC
2199 add nPC, 0x4 ; nPC := nPC + 4
2200 SX18_4N Imm ; Sign Extend Imm * 4
2201 mov TMP, 0x4 ; TMP := 4
2202 cmp R(rS), 0 ; If Regs[rS] < 0:
2203 cmovl TMP, Imm ; ... then TMP := Imm
2204 add nPC, TMP ; nPC := nPC + TMP
2205 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2206 jmp _end_cycle
2207 ;-----------------------------------------------------------------------------
2208
2209 ;-----------------------------------------------------------------------------
2210 ; BGEZ -- Branch on greater than or equal to zero.
2211 ; Branches if the register is greater than or equal to zero
2212 ; Operation: if $s >= 0 advance_pc(offset << 2)); else advance_pc(4);
2213 ; Syntax: bgez $s, offset
2214 ; Encoding: 0000 01ss sss0 0001 iiii iiii iiii iiii
2215 ;-----------------------------------------------------------------------------
2216 align GRAIN, db 0x90
2217 _b_bgez:
2218 IType_I_S_Only ; load rS and Imm Fields
2219 mov nPC, PC ; nPC := PC
2220 add nPC, 0x4 ; nPC := nPC + 4
2221 SX18_4N Imm ; Sign Extend Imm * 4
2222 mov TMP, 0x4 ; TMP := 4
2223 cmp R(rS), 0 ; If Regs[rS] >= 0:
2224 cmovge TMP, Imm ; ... then TMP := Imm
2225 add nPC, TMP ; nPC := nPC + TMP
2226 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2227 jmp _end_cycle
2228 ;-----------------------------------------------------------------------------
2229
2230 ;-----------------------------------------------------------------------------
2231 ; BLTZL - Branch on Less Than Zero Likely.
2232 ; Test a register, then do a PC-relative conditional branch;
2233 ; execute the delay slot only if the branch is taken.
2234 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2235 ; added to the address of the instruction following the branch (not the branch
2236 ; itself), in the branch delay slot, to form a PC-relative effective target
2237 ; address. If the contents of rS are less than zero (sign bit is 1), branch to
2238 ; the effective target address after the instruction in the delay slot is
2239 ; executed. If the branch is not taken, the instruction in the delay slot is
2240 ; not executed.
2241 ; Operation: if rS < 0 then PC = PC + sign_extend(offset)
2242 ; else: nullify_current_instruction
2243 ; Syntax: bltzl $s, offset
2244 ; Encoding: 0000 01ss sss0 0010 iiii iiii iiii iiii
2245 ;-----------------------------------------------------------------------------
2246 align GRAIN, db 0x90
2247 _b_bltzl:
2248 IType_S_Only ; load only rS Field just now
2249 cmp R(rS), 0 ; CMP(Regs[rS], 0)
2250 jnl _i_bltzl_not_taken ; If !(Regs[rS] < 0) then NotTaken
2251 ; Taken:
2252 IType_I_Only ; load only Imm Field just now
2253 SX18_4N Imm ; Sign Extend Imm * 4
2254 mov nPC, PC ; nPC := PC
2255 add nPC, 0x4 ; nPC := nPC + 4
2256 add nPC, Imm ; nPC := nPC + Offset
2257 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2258 jmp _end_cycle
2259 ; Not Taken:
2260 _i_bltzl_not_taken:
2261 add PC, 0x4 ; PC := PC + 4
2262 jmp _end_cycle
2263 ;-----------------------------------------------------------------------------
2264
2265 ;-----------------------------------------------------------------------------
2266 ; BGEZL - Branch on Greater Than or Equal to Zero Likely.
2267 ; Test a register, then do a PC-relative conditional branch;
2268 ; execute the delay slot only if the branch is taken.
2269 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2270 ; added to the address of the instruction following the branch (not the branch
2271 ; itself), in the branch delay slot, to form a PC-relative effective target
2272 ; address. If the contents of rS are greater than or equal to zero
2273 ; (sign bit is 0), branch to the effective target address after the
2274 ; instruction in the delay slot is executed. If the branch is not taken, the
2275 ; instruction in the delay slot is not executed.
2276 ; Operation: if rS >= 0 then PC = PC + sign_extend(offset)
2277 ; else: nullify_current_instruction
2278 ; Syntax: bgezl $s, offset
2279 ; Encoding: 0000 01ss sss0 0011 iiii iiii iiii iiii
2280 ;-----------------------------------------------------------------------------
2281 align GRAIN, db 0x90
2282 _b_bgezl:
2283 IType_S_Only ; Load only rS Field just now
2284 cmp R(rS), 0 ; CMP(Regs[rS], 0)
2285 jnge _i_bgezl_not_taken ; If !(Regs[rS] >= 0) then NotTaken
2286 ; Taken:
2287 IType_I_Only ; Load only Imm Field just now
2288 SX18_4N Imm ; Sign Extend Imm * 4
2289 mov nPC, PC ; nPC := PC
2290 add nPC, 0x4 ; nPC := nPC + 4
2291 add nPC, Imm ; nPC := nPC + Offset
2292 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2293 jmp _end_cycle
2294 ; Not Taken:
2295 _i_bgezl_not_taken:
2296 add PC, 0x4 ; PC := PC + 4
2297 jmp _end_cycle
2298 ;-----------------------------------------------------------------------------
2299
2300 ;-----------------------------------------------------------------------------
2301 ; BLTZAL -- Branch on less than zero and link.
2302 ; Branches if the register is less than zero and saves the return address
2303 ; in $31
2304 ; Operation: if $s < 0 $31 = PC + 8 (or nPC + 4); advance_pc(offset << 2));
2305 ; else advance_pc(4);
2306 ; Syntax: bltzal $s, offset
2307 ; Encoding: 0000 01ss sss1 0000 iiii iiii iiii iiii
2308 ;-----------------------------------------------------------------------------
2309 align GRAIN, db 0x90
2310 _b_bltzal:
2311 IType_I_S_Only ; Load rS and Imm Fields
2312 mov nPC, PC ; nPC := PC
2313 add nPC, 0x4 ; nPC := nPC + 4
2314 mov TMP, nPC ; TMP := nPC
2315 add TMP, 0x4 ; TMP := TMP + 4
2316 mov R(31), TMP ; Regs[31] := TMP
2317 SX18_4N Imm ; Sign Extend Imm * 4
2318 mov TMP, 0x4 ; TMP := 4
2319 cmp R(rS), 0 ; If Regs[rS] < 0:
2320 cmovl TMP, Imm ; ... then TMP := Imm
2321 add nPC, TMP ; nPC := nPC + TMP
2322 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2323 jmp _end_cycle
2324 ;-----------------------------------------------------------------------------
2325
2326 ;-----------------------------------------------------------------------------
2327 ; BGEZAL -- Branch on greater than or equal to zero and link.
2328 ; Branches if the register is greater than or equal to zero and saves the
2329 ; return address in $31
2330 ; Operation: if $s >= 0 $31 = PC + 8 (or nPC + 4); advance_pc(offset << 2));
2331 ; else advance_pc(4);
2332 ; Syntax: bgezal $s, offset
2333 ; Encoding: 0000 01ss sss1 0001 iiii iiii iiii iiii
2334 ;-----------------------------------------------------------------------------
2335 align GRAIN, db 0x90
2336 _b_bgezal:
2337 IType_I_S_Only ; Load rS and Imm Fields
2338 mov nPC, PC ; nPC := PC
2339 add nPC, 0x4 ; nPC := nPC + 4
2340 mov TMP, nPC ; TMP := nPC
2341 add TMP, 0x4 ; TMP := TMP + 4
2342 mov R(31), TMP ; Regs[31] := TMP
2343 SX18_4N Imm ; Sign Extend Imm * 4
2344 mov TMP, 0x4 ; TMP := 4
2345 cmp R(rS), 0 ; If Regs[rS] < 0:
2346 cmovnl TMP, Imm ; ... then TMP := Imm
2347 add nPC, TMP ; nPC := nPC + TMP
2348 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2349 jmp _end_cycle
2350 ;-----------------------------------------------------------------------------
-
+ 5B25235B8644D82E985ED6CC354E5E6E0D94AAAF0D0B5A7B33D8A5586CF67A90F13885398E5C10B935C9EE991B1CC720AE9B832DFF9961D6090CF5E17A0445B9
m/mipsinst/i_instrs.asm
(0 . 0)(1 . 1123)
2355 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2356 ;; ;;
2357 ;; This file is part of 'M', a MIPS system emulator. ;;
2358 ;; ;;
2359 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
2360 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
2361 ;; ;;
2362 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
2363 ;; distribute this software ; Should you use this software for any purpose, ;;
2364 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
2365 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
2366 ;; continue doing so for the indefinite future. In any case, please ;;
2367 ;; always : read and understand any software ; verify any PGP signatures ;;
2368 ;; that you use - for any purpose. ;;
2369 ;; ;;
2370 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
2371 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2372
2373 ;; TODO: 1) Trap for ADDI (gcc 4.8.1 doesn't appear to use, but it exists...)
2374 ;; 2) Tests!!!
2375
2376 ;------------------------
2377 ; I-Type Instructions : |
2378 ;------------------------
2379
2380 ;-----------------------------------------------------------------------------
2381 section .rodata
2382 align GRAIN, db 0x90
2383 _I_Table:
2384 A32 _i_000000 ; 0x00 : All R-Type Instructions
2385 A32 _i_000001 ; 0x01 : bltz, bgez, bltzl, bgezl, bltzal, bgezal
2386 A32 _i_j ; 0x02 : j (000010??????????????????????????)
2387 A32 _i_jal ; 0x03 : jal (000011??????????????????????????)
2388 A32 _i_beq ; 0x04 : beq (000100??????????????????????????)
2389 A32 _i_bne ; 0x05 : bne (000101??????????????????????????)
2390 A32 _i_blez ; 0x06 : blez (000110??????????????????????????)
2391 A32 _i_bgtz ; 0x07 : bgtz (000111??????????????????????????)
2392 A32 _i_addi ; 0x08 : addi (001000??????????????????????????)
2393 A32 _i_addiu ; 0x09 : addiu (001001??????????????????????????)
2394 A32 _i_slti ; 0x0a : slti (001010??????????????????????????)
2395 A32 _i_sltiu ; 0x0b : sltiu (001011??????????????????????????)
2396 A32 _i_andi ; 0x0c : andi (001100??????????????????????????)
2397 A32 _i_ori ; 0x0d : ori (001101??????????????????????????)
2398 A32 _i_xori ; 0x0e : xori (001110??????????????????????????)
2399 A32 _i_lui ; 0x0f : lui (001111??????????????????????????)
2400 A32 _i_010000 ; 0x10 : mfc0, mtc0, tlbwi, tlbwr, tlbp, eret, wait
2401 A32 _bad ; 0x11 : UNDEFINED
2402 A32 _bad ; 0x12 : UNDEFINED
2403 A32 _bad ; 0x13 : UNDEFINED
2404 A32 _i_beql ; 0x14 : beql (010100??????????????????????????)
2405 A32 _i_bnel ; 0x15 : bnel (010101??????????????????????????)
2406 A32 _i_blezl ; 0x16 : blezl (010110??????????????????????????)
2407 A32 _i_bgtzl ; 0x17 : bgtzl (010111?????00000????????????????)
2408 A32 _bad ; 0x18 : UNDEFINED
2409 A32 _bad ; 0x19 : UNDEFINED
2410 A32 _bad ; 0x1a : UNDEFINED
2411 A32 _bad ; 0x1b : UNDEFINED
2412 A32 _i_mul ; 0x1c : mul (011100???????????????00000000010)
2413 A32 _bad ; 0x1d : UNDEFINED
2414 A32 _bad ; 0x1e : UNDEFINED
2415 A32 _bad ; 0x1f : UNDEFINED
2416 A32 _i_lb ; 0x20 : lb (100000??????????????????????????)
2417 A32 _i_lh ; 0x21 : lh (100001??????????????????????????)
2418 A32 _i_lwl ; 0x22 : lwl (100010??????????????????????????)
2419 A32 _i_lw ; 0x23 : lw (100011??????????????????????????)
2420 A32 _i_lbu ; 0x24 : lbu (100100??????????????????????????)
2421 A32 _i_lhu ; 0x25 : lhu (100101??????????????????????????)
2422 A32 _i_lwr ; 0x26 : lwr (100110??????????????????????????)
2423 A32 _bad ; 0x27 : UNDEFINED
2424 A32 _i_sb ; 0x28 : sb (101000??????????????????????????)
2425 A32 _i_sh ; 0x29 : sh (101001??????????????????????????)
2426 A32 _i_swl ; 0x2a : swl (101010??????????????????????????)
2427 A32 _i_sw ; 0x2b : sw (101011??????????????????????????)
2428 A32 _bad ; 0x2c : UNDEFINED
2429 A32 _bad ; 0x2d : UNDEFINED
2430 A32 _i_swr ; 0x2e : swr (101110??????????????????????????)
2431 A32 _i_cache ; 0x2f : cache (101111??????????????????????????)
2432 A32 _i_ll ; 0x30 : ll (110000??????????????????????????)
2433 A32 _bad ; 0x31 : UNDEFINED
2434 A32 _bad ; 0x32 : UNDEFINED
2435 A32 _i_pref ; 0x33 : pref (110011??????????????????????????)
2436 A32 _bad ; 0x34 : UNDEFINED
2437 A32 _bad ; 0x35 : UNDEFINED
2438 A32 _bad ; 0x36 : UNDEFINED
2439 A32 _bad ; 0x37 : UNDEFINED
2440 A32 _i_sc ; 0x38 : sc (111000??????????????????????????)
2441 A32 _bad ; 0x39 : UNDEFINED
2442 A32 _bad ; 0x3a : UNDEFINED
2443 A32 _bad ; 0x3b : UNDEFINED
2444 A32 _bad ; 0x3c : UNDEFINED
2445 A32 _bad ; 0x3d : UNDEFINED
2446 A32 _bad ; 0x3e : UNDEFINED
2447 A32 _bad ; 0x3f : UNDEFINED
2448 ;-----------------------------------------------------------------------------
2449 align GRAIN, db 0x90
2450 _MFC0_Table:
2451 A32 _mfc0_r00 ; 0x00
2452 A32 _mfc0_r01 ; 0x01
2453 A32 _mfc0_r02 ; 0x02
2454 A32 _mfc0_r03 ; 0x03
2455 A32 _mfc0_r04 ; 0x04
2456 A32 _mfc0_r05 ; 0x05
2457 A32 _mfc0_r06 ; 0x06
2458 A32 _mfc0_r07 ; 0x07
2459 A32 _mfc0_r08 ; 0x08
2460 A32 _mfc0_r09 ; 0x09
2461 A32 _mfc0_r10 ; 0x0a
2462 A32 _mfc0_r11 ; 0x0b
2463 A32 _mfc0_r12 ; 0x0c
2464 A32 _mfc0_r13 ; 0x0d
2465 A32 _mfc0_r14 ; 0x0e
2466 A32 _mfc0_r15 ; 0x0f
2467 A32 _mfc0_r16 ; 0x10
2468 A32 _mfc0_r17 ; 0x11
2469 A32 _mfc0_r18 ; 0x12
2470 A32 _mfc0_r19 ; 0x13
2471 A32 _mfc0_r20 ; 0x14
2472 A32 _mfc0_r21 ; 0x15
2473 A32 _mfc0_r22 ; 0x16
2474 A32 _mfc0_r23 ; 0x17
2475 A32 _mfc0_r24 ; 0x18
2476 A32 _mfc0_r25 ; 0x19
2477 A32 _mfc0_r26 ; 0x1a
2478 A32 _mfc0_r27 ; 0x1b
2479 A32 _mfc0_r28 ; 0x1c
2480 A32 _mfc0_r29 ; 0x1d
2481 A32 _mfc0_r30 ; 0x1e
2482 A32 _mfc0_r31 ; 0x1f
2483 ;-----------------------------------------------------------------------------
2484 align GRAIN, db 0x90
2485 _MTC0_Table:
2486 A32 _mtc0_r00 ; 0x00
2487 A32 _mtc0_r01 ; 0x01
2488 A32 _mtc0_r02 ; 0x02
2489 A32 _mtc0_r03 ; 0x03
2490 A32 _mtc0_r04 ; 0x04
2491 A32 _mtc0_r05 ; 0x05
2492 A32 _mtc0_r06 ; 0x06
2493 A32 _mtc0_r07 ; 0x07
2494 A32 _mtc0_r08 ; 0x08
2495 A32 _mtc0_r09 ; 0x09
2496 A32 _mtc0_r10 ; 0x0a
2497 A32 _mtc0_r11 ; 0x0b
2498 A32 _mtc0_r12 ; 0x0c
2499 A32 _mtc0_r13 ; 0x0d
2500 A32 _mtc0_r14 ; 0x0e
2501 A32 _mtc0_r15 ; 0x0f
2502 A32 _mtc0_r16 ; 0x10
2503 A32 _mtc0_r17 ; 0x11
2504 A32 _mtc0_r18 ; 0x12
2505 A32 _mtc0_r19 ; 0x13
2506 A32 _mtc0_r20 ; 0x14
2507 A32 _mtc0_r21 ; 0x15
2508 A32 _mtc0_r22 ; 0x16
2509 A32 _mtc0_r23 ; 0x17
2510 A32 _mtc0_r24 ; 0x18
2511 A32 _mtc0_r25 ; 0x19
2512 A32 _mtc0_r26 ; 0x1a
2513 A32 _mtc0_r27 ; 0x1b
2514 A32 _mtc0_r28 ; 0x1c
2515 A32 _mtc0_r29 ; 0x1d
2516 A32 _mtc0_r30 ; 0x1e
2517 A32 _mtc0_r31 ; 0x1f
2518 ;-----------------------------------------------------------------------------
2519
2520 section .text
2521
2522 ;------------------------
2523 ; Invalid Instruction : |
2524 ;------------------------
2525 align GRAIN, db 0x90
2526 _bad:
2527 SetEXC EXC_RI ; Set the EXC_RI Exception
2528 jmp _Handle_Exception ; Go straight to exception handler.
2529 ;-----------------------------------------------------------------------------
2530
2531 ;-----------------------------------------------------------------------------
2532 ; Eat 000000?????????????????????????? (R-Type) Instructions:
2533 ;-----------------------------------------------------------------------------
2534 align GRAIN, db 0x90
2535 _i_000000:
2536 mov eax, r_I ; Get the original instruction :
2537 and eax, 0x3F ; Get funct field, (lower 6 bits) ;
2538 JTABLE eax, _R_Table ; Dispatch on funct-field via R-Table.
2539 ;-----------------------------------------------------------------------------
2540
2541 ;-----------------------------------------------------------------------------
2542 ; Eat 000001?????QQQQQ???????????????? Branch Instructions :
2543 ; i.e. bltz, bgez, bltzl, bgezl, bltzal, bgezal
2544 ;-----------------------------------------------------------------------------
2545 align GRAIN, db 0x90
2546 _i_000001:
2547 mov eax, r_I ; Get the original instruction :
2548 shr eax, 16 ; Get the 5-bit field QQQQQ
2549 and eax, 0x1F ; which distinguishes these;
2550 JTABLE eax, _B_Table ; Dispatch via B-Table.
2551 ;-----------------------------------------------------------------------------
2552
2553 ;-----------------------------------------------------------------------------
2554 ; Eat 010000?????????????????????????? Misc. Instructions :
2555 ; mfc0, mtc0, tlbwi, tlbwr, tlbp, eret, wait
2556 ; PRIVILEGED (permitted in Kernel Mode only.)
2557 ;-----------------------------------------------------------------------------
2558 align GRAIN, db 0x90
2559 _i_010000:
2560 PRIVILEGED ; Permitted in Kernel Mode only.
2561 mov eax, r_I ; Get the original instruction :
2562 shr eax, 5 ; Get the top 27 bits
2563 cmp eax, 0x2100000 ; Equal 010000100000000000000000000..?
2564 je _tlbwi_tlbwr_tlbp_eret ; 010000100000000000000000000QQQQQ
2565 ;; At this point, we have either mfc0, mtc0, wait, or a bad instr:
2566 shr eax, 16 ; We already shifted by 5, so now 21:
2567 cmp eax, 0x200 ; ... are they equal to 0b01000000000 ?
2568 je _m_mfc0 ; mfc0 (01000000000?????????????????????)
2569 cmp eax, 0x204 ; ... are they equal to 0b01000000100 ?
2570 je _m_mtc0 ; mtc0 (01000000100?????????????????????)
2571 ;; Now determine if it is 'wait' (0100001???????????????????100000) :
2572 mov eax, r_I ; Get the original instruction :
2573 and eax, 0xFE00003F ; Get top 7 bits and bottom 6 bits only
2574 cmp eax, 0x42000020 ; Top must be 0b0100001, bottom 0b100000
2575 je _m_wait ; wait (0100001???????????????????100000)
2576 ;; Now, if it wasn't the 'wait' instruction, we must then have a turd:
2577 jmp _bad ; If we're here : undefined inst.
2578 ;-----------------------------------------------------------------------------
2579
2580 ;-----------------------------------------------------------------------------
2581 ; Eat 010000100000000000000000000QQQQQ Instructions (via _i_010000) :
2582 ; tlbwi, tlbwr, tlbp, eret
2583 ;-----------------------------------------------------------------------------
2584 align GRAIN, db 0x90
2585 _tlbwi_tlbwr_tlbp_eret:
2586 mov eax, r_I ; Get the original instruction :
2587 and eax, 0x1F ; Get the the 5-bit field QQQQQ from it
2588 JTABLE eax, _M_Table ; Dispatch via M-Table.
2589 ;-----------------------------------------------------------------------------
2590
2591 ;-----------------------------------------------------------------------------
2592 ; J -- Jump.
2593 ; Jumps to the calculated address.
2594 ; Operation: PC = nPC; nPC = (PC & 0xF0000000) | (target << 2);
2595 ; Syntax: j target
2596 ; Encoding: 0000 10ii iiii iiii iiii iiii iiii iiii
2597 ;-----------------------------------------------------------------------------
2598 align GRAIN, db 0x90
2599 _i_j:
2600 JType ; load J Field (ii..iii << 2)
2601 mov nPC, PC ; nPC := PC
2602 and nPC, 0xF0000000 ; keep only top 4 bits of nPC, zero rest
2603 or nPC, JTarg ; nPC := nPC | ( target << 2 )
2604 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2605 jmp _end_cycle
2606 ;-----------------------------------------------------------------------------
2607
2608 ;-----------------------------------------------------------------------------
2609 ; JAL -- Jump and link.
2610 ; Jumps to the calculated address and stores the return address in $31.
2611 ; Operation: $31 = PC + 8 (or nPC + 4);
2612 ; PC = nPC;
2613 ; nPC = (PC & 0xF0000000) | (target << 2);
2614 ; Syntax: jal target
2615 ; Encoding: 0000 11ii iiii iiii iiii iiii iiii iiii
2616 ;-----------------------------------------------------------------------------
2617 align GRAIN, db 0x90
2618 _i_jal:
2619 JType ; load J Field (ii..iii << 2)
2620 mov TMP, PC ; TMP := PC
2621 add TMP, 0x8 ; TMP := TMP + 8
2622 mov R(31), TMP ; Regs[31] := TMP
2623 sub TMP, 0x8 ; TMP := TMP - 8
2624 and TMP, 0xF0000000 ; keep only top 4 bits of TMP, zero rest
2625 or TMP, JTarg ; TMP := TMP | ( target << 2 )
2626 mov nPC, TMP ; nPC := TMP
2627 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2628 jmp _end_cycle
2629 ;-----------------------------------------------------------------------------
2630
2631 ;-----------------------------------------------------------------------------
2632 ; BEQ -- Branch on equal.
2633 ; Branches if the two registers are equal.
2634 ; Operation: if $s == $t advance_pc(offset << 2));
2635 ; else advance_pc(4);
2636 ; Syntax: beq $s, $t, offset
2637 ; Encoding: 0001 00ss ssst tttt iiii iiii iiii iiii
2638 ;-----------------------------------------------------------------------------
2639 align GRAIN, db 0x90
2640 _i_beq:
2641 IType ; Load Imm, rS, rT Fields
2642 mov nPC, PC ; nPC := PC
2643 add nPC, 0x4 ; nPC := nPC + 4
2644 SX18_4N Imm ; Sign Extend Imm * 4
2645 mov TMP, R(rS) ; TMP := Regs[rS]
2646 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2647 mov TMP, 0x4 ; TMP := 4
2648 cmove TMP, Imm ; If Regs[rS] = Regs[rT], TMP := Imm
2649 add nPC, TMP ; nPC := nPC + TMP
2650 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2651 jmp _end_cycle
2652 ;-----------------------------------------------------------------------------
2653
2654 ;-----------------------------------------------------------------------------
2655 ; BNE -- Branch on not equal.
2656 ; Branches if the two registers are not equal.
2657 ; Operation: if $s != $t advance_pc(offset << 2));
2658 ; else advance_pc(4);
2659 ; Syntax: bne $s, $t, offset
2660 ; Encoding: 0001 01ss ssst tttt iiii iiii iiii iiii
2661 ;-----------------------------------------------------------------------------
2662 align GRAIN, db 0x90
2663 _i_bne:
2664 IType ; Load Imm, rS, rT Fields
2665 mov nPC, PC ; nPC := PC
2666 add nPC, 0x4 ; nPC := nPC + 4
2667 SX18_4N Imm ; Sign Extend Imm * 4
2668 mov TMP, R(rS) ; TMP := Regs[rS]
2669 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2670 mov TMP, 0x4 ; TMP := 4
2671 cmovne TMP, Imm ; If Regs[rS] != Regs[rT], TMP := Imm
2672 add nPC, TMP ; nPC := nPC + TMP
2673 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2674 jmp _end_cycle
2675 ;-----------------------------------------------------------------------------
2676
2677 ;-----------------------------------------------------------------------------
2678 ; BLEZ -- Branch on less than or equal to zero.
2679 ; Branches if the register is less than or equal to zero
2680 ; Operation: if $s <= 0 advance_pc(offset << 2));
2681 ; else advance_pc(4);
2682 ; Syntax: blez $s, offset
2683 ; Encoding: 0001 10ss sss0 0000 iiii iiii iiii iiii
2684 ;-----------------------------------------------------------------------------
2685 align GRAIN, db 0x90
2686 _i_blez:
2687 IType_I_S_Only ; load rS and Imm Fields
2688 mov nPC, PC ; nPC := PC
2689 add nPC, 0x4 ; nPC := nPC + 4
2690 SX18_4N Imm ; Sign Extend Imm * 4
2691 mov TMP, 0x4 ; TMP := 4
2692 cmp R(rS), 0 ; If Regs[rS] <= 0:
2693 cmovle TMP, Imm ; ... then TMP := Imm
2694 add nPC, TMP ; nPC := nPC + TMP
2695 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2696 jmp _end_cycle
2697 ;-----------------------------------------------------------------------------
2698
2699 ;-----------------------------------------------------------------------------
2700 ; BGTZ -- Branch on greater than zero.
2701 ; Branches if the register is greater than zero
2702 ; Operation: if $s > 0 advance_pc(offset << 2));
2703 ; else advance_pc(4);
2704 ; Syntax: bgtz $s, offset
2705 ; Encoding: 0001 11ss sss0 0000 iiii iiii iiii iiii
2706 ;-----------------------------------------------------------------------------
2707 align GRAIN, db 0x90
2708 _i_bgtz:
2709 IType_I_S_Only ; load rS and Imm Fields
2710 mov nPC, PC ; nPC := PC
2711 add nPC, 0x4 ; nPC := nPC + 4
2712 SX18_4N Imm ; Sign Extend Imm * 4
2713 mov TMP, 0x4 ; TMP := 4
2714 cmp R(rS), 0 ; If Regs[rS] > 0:
2715 cmovg TMP, Imm ; ... then TMP := Imm
2716 add nPC, TMP ; nPC := nPC + TMP
2717 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2718 jmp _end_cycle
2719 ;-----------------------------------------------------------------------------
2720
2721 ;-----------------------------------------------------------------------------
2722 ; ADDI -- Add immediate (with overflow).
2723 ; Adds a register and a sign-extended immediate value and stores the
2724 ; result in a register
2725 ; Operation: $t = $s + imm; advance_pc(4);
2726 ; Syntax: addi $t, $s, imm
2727 ; Encoding: 0010 00ss ssst tttt iiii iiii iiii iiii
2728 ;-----------------------------------------------------------------------------
2729 ; TODO: untested
2730 align GRAIN, db 0x90
2731 _i_addi:
2732 ; UNDONE_INST
2733 IType ; Load Imm, rS, rT Fields
2734 SX16 Imm ; Sign-extend the Imm offset
2735 mov TMP, R(rS) ; TMP := Regs[rS]
2736 add TMP, Imm ; TMP := TMP + Imm
2737 ; TODO: detect and trap overflow
2738 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2739 jmp _end_cycle
2740 ;-----------------------------------------------------------------------------
2741
2742 ;-----------------------------------------------------------------------------
2743 ; ADDIU -- Add immediate unsigned (no overflow).
2744 ; Adds a register and a sign-extended immediate value and stores the
2745 ; result in a register
2746 ; Operation: $t = $s + imm; advance_pc(4);
2747 ; Syntax: addiu $t, $s, imm
2748 ; Encoding: 0010 01ss ssst tttt iiii iiii iiii iiii
2749 ;-----------------------------------------------------------------------------
2750 align GRAIN, db 0x90
2751 _i_addiu:
2752 IType ; Load Imm, rS, rT Fields
2753 SX16 Imm ; Sign-extend the Imm offset
2754 mov TMP, R(rS) ; TMP := Regs[rS]
2755 add TMP, Imm ; TMP := TMP + Imm
2756 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2757 jmp _end_cycle
2758 ;-----------------------------------------------------------------------------
2759
2760 ;-----------------------------------------------------------------------------
2761 ; SLTI -- Set on less than immediate (signed).
2762 ; If $s is less than immediate, $t is set to one. It gets zero otherwise.
2763 ; Operation: if $s < imm $t = 1; advance_pc(4);
2764 ; else $t = 0; advance_pc(4);
2765 ; Syntax: slti $t, $s, imm
2766 ; Encoding: 0010 10ss ssst tttt iiii iiii iiii iiii
2767 ;-----------------------------------------------------------------------------
2768 align GRAIN, db 0x90
2769 _i_slti:
2770 IType ; Load Imm, rS, rT Fields
2771 SX16 Imm ; Sign-extend the Imm offset
2772 xor TMP, TMP ; Clear TMP
2773 cmp R(rS), Imm ; CMP(R(rS), Imm)
2774 setl TMP_LowByte ; if $s <(sgn) imm then TMP := 1; else 0
2775 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2776 jmp _end_cycle
2777 ;-----------------------------------------------------------------------------
2778
2779 ;-----------------------------------------------------------------------------
2780 ; SLTIU -- Set on less than immediate unsigned.
2781 ; If $s is less than the unsigned immediate, $t is set to one.
2782 ; It gets zero otherwise.
2783 ; Operation: if $s < imm $t = 1; advance_pc(4);
2784 ; else $t = 0; advance_pc(4);
2785 ; Syntax: sltiu $t, $s, imm
2786 ; Encoding: 0010 11ss ssst tttt iiii iiii iiii iiii
2787 ;-----------------------------------------------------------------------------
2788 ; Apparently even here we sign-extend the immediate.
2789 align GRAIN, db 0x90
2790 _i_sltiu:
2791 IType ; Load Imm, rS, rT Fields
2792 SX16 Imm ; Sign-extend the Imm offset
2793 xor TMP, TMP ; Clear TMP
2794 cmp R(rS), Imm ; CMP(R(rS), Imm)
2795 setb TMP_LowByte ; if $s < imm then TMP := 1; else 0
2796 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2797 jmp _end_cycle
2798 ;-----------------------------------------------------------------------------
2799
2800 ;-----------------------------------------------------------------------------
2801 ; ANDI -- Bitwise AND immediate.
2802 ; Bitwise ANDs a register and an immediate value and stores the result
2803 ; in a register
2804 ; Operation: $t = $s & imm; advance_pc(4);
2805 ; Syntax: andi $t, $s, imm
2806 ; Encoding: 0011 00ss ssst tttt iiii iiii iiii iiii
2807 ;-----------------------------------------------------------------------------
2808 align GRAIN, db 0x90
2809 _i_andi:
2810 IType ; Load Imm, rS, rT Fields
2811 mov TMP, R(rS) ; TMP := Regs[rS]
2812 and TMP, Imm ; TMP := TMP & Imm
2813 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2814 jmp _end_cycle
2815 ;-----------------------------------------------------------------------------
2816
2817 ;-----------------------------------------------------------------------------
2818 ; ORI -- Bitwise OR immediate.
2819 ; Bitwise OrS a register and an immediate value and stores the result
2820 ; in a register
2821 ; Operation: $t = $s | imm; advance_pc(4);
2822 ; Syntax: ori $t, $s, imm
2823 ; Encoding: 0011 01ss ssst tttt iiii iiii iiii iiii
2824 ;-----------------------------------------------------------------------------
2825 align GRAIN, db 0x90
2826 _i_ori:
2827 IType ; Load Imm, rS, rT Fields
2828 mov TMP, R(rS) ; TMP := Regs[rS]
2829 or TMP, Imm ; TMP := TMP | Imm
2830 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2831 jmp _end_cycle
2832 ;-----------------------------------------------------------------------------
2833
2834 ;-----------------------------------------------------------------------------
2835 ; XORI -- Bitwise Exclusive Or immediate.
2836 ; Bitwise XOrS a register and an immediate value and stores the
2837 ; result in a register
2838 ; Operation: $t = $s ^ imm; advance_pc(4);
2839 ; Syntax: xori $t, $s, imm
2840 ; Encoding: 0011 10ss ssst tttt iiii iiii iiii iiii
2841 ;-----------------------------------------------------------------------------
2842 align GRAIN, db 0x90
2843 _i_xori:
2844 IType ; Load Imm, rS, rT Fields
2845 mov TMP, R(rS) ; TMP := Regs[rS]
2846 xor TMP, Imm ; TMP := TMP ^ Imm
2847 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2848 jmp _end_cycle
2849 ;-----------------------------------------------------------------------------
2850
2851 ;-----------------------------------------------------------------------------
2852 ; LUI -- Load upper immediate.
2853 ; The immediate value is shifted left 16 bits and stored in the register.
2854 ; The lower 16 bits are zeroes.
2855 ; Operation: $t = (imm << 16); advance_pc(4);
2856 ; Syntax: lui $t, imm
2857 ; Encoding: 0011 11-- ---t tttt iiii iiii iiii iiii
2858 ;-----------------------------------------------------------------------------
2859 align GRAIN, db 0x90
2860 _i_lui:
2861 IType_I_T_Only ; Load Imm and rT Fields
2862 mov TMP, Imm ; TMP := Imm
2863 shl TMP, 16 ; TMP := TMP << 16
2864 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2865 jmp _end_cycle
2866 ;-----------------------------------------------------------------------------
2867
2868 ;-----------------------------------------------------------------------------
2869 ; BEQL - Branch on Equal Likely.
2870 ; Compare registers, then do a PC-relative conditional branch;
2871 ; execute the delay slot only if the branch is taken.
2872 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2873 ; added to the address of the instruction following the branch (not the
2874 ; branch itself), in the branch delay slot, to form a PC-relative effective
2875 ; target address. If the contents of rS and rT are equal, branch to the target
2876 ; address after the instruction in the delay slot is executed. If the branch
2877 ; is not taken, the instruction in the delay slot is not executed.
2878 ; Operation: if rS = rT then branch_likely
2879 ; Syntax: beql $s, $t, offset
2880 ; Encoding: 0101 00ss ssst tttt iiii iiii iiii iiii
2881 ;-----------------------------------------------------------------------------
2882 align GRAIN, db 0x90
2883 _i_beql:
2884 IType ; Load Imm, rS, rT Fields
2885 mov TMP, R(rS) ; TMP := Regs[rS]
2886 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2887 jne _i_beql_not_taken ; If !(TMP = Regs[rT]) then NotTaken
2888 ; Taken:
2889 SX18_4N Imm ; Sign Extend Imm * 4
2890 mov nPC, PC ; nPC := PC
2891 add nPC, 0x4 ; nPC := nPC + 4
2892 add nPC, Imm ; nPC := nPC + Offset
2893 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2894 jmp _end_cycle
2895 ; Not Taken:
2896 _i_beql_not_taken:
2897 add PC, 0x4 ; PC := PC + 4
2898 jmp _end_cycle
2899 ;-----------------------------------------------------------------------------
2900
2901 ;-----------------------------------------------------------------------------
2902 ; BNEL - Branch on Not Equal Likely.
2903 ; Compare registers, then do a PC-relative conditional branch;
2904 ; execute the delay slot only if the branch is taken.
2905 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2906 ; added to the address of the instruction following the branch (not the
2907 ; branch itself), in the branch delay slot, to form a PC-relative effective
2908 ; target address. If the contents of rS and rT are NOT equal, branch to the
2909 ; target address after the instruction in the delay slot is executed. If the
2910 ; branch is not taken, the instruction in the delay slot is not executed.
2911 ; Operation: if rS != rT then branch_likely
2912 ; Syntax: bnel $s, $t, offset
2913 ; Encoding: 0101 01ss ssst tttt iiii iiii iiii iiii
2914 ;-----------------------------------------------------------------------------
2915 align GRAIN, db 0x90
2916 _i_bnel:
2917 IType ; Load Imm, rS, rT Fields
2918 mov TMP, R(rS) ; TMP := Regs[rS]
2919 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2920 je _i_bnel_not_taken ; If !(TMP != Regs[rT]) then NotTaken
2921 ; Taken:
2922 SX18_4N Imm ; Sign Extend Imm * 4
2923 mov nPC, PC ; nPC := PC
2924 add nPC, 0x4 ; nPC := nPC + 4
2925 add nPC, Imm ; nPC := nPC + Offset
2926 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2927 jmp _end_cycle
2928 ; Not Taken:
2929 _i_bnel_not_taken:
2930 add PC, 0x4 ; PC := PC + 4
2931 jmp _end_cycle
2932 ;-----------------------------------------------------------------------------
2933
2934 ;-----------------------------------------------------------------------------
2935 ; BLEZL - Branch on Less Than or Equal to Zero Likely.
2936 ; Test a register, then do a PC-relative conditional branch;
2937 ; execute the delay slot only if the branch is taken.
2938 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2939 ; added to the address of the instruction following the branch (not the branch
2940 ; itself), in the branch delay slot, to form a PC-relative effective target
2941 ; address. If the contents of rS are less than or equal to zero (sign bit is
2942 ; 1 or value is zero), branch to the effective target address after the
2943 ; instruction in the delay slot is executed. If the branch is not taken, the
2944 ; instruction in the delay slot is not executed.
2945 ; Operation: If rS <= 0 then branch_likely
2946 ; Syntax: bltzl $s, offset
2947 ; Encoding: 0101 10ss sss0 0000 iiii iiii iiii iiii
2948 ;-----------------------------------------------------------------------------
2949 align GRAIN, db 0x90
2950 _i_blezl:
2951 IType_S_Only ; load only rS Field just now
2952 cmp R(rS), 0 ; CMP(Regs[rS], 0)
2953 jnle _i_blezl_not_taken ; If !(Regs[rS] <= 0) then NotTaken
2954 ; Taken:
2955 IType_I_Only ; load only Imm Field just now
2956 SX18_4N Imm ; Sign Extend Imm * 4
2957 mov nPC, PC ; nPC := PC
2958 add nPC, 0x4 ; nPC := nPC + 4
2959 add nPC, Imm ; nPC := nPC + Offset
2960 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2961 jmp _end_cycle
2962 ; Not Taken:
2963 _i_blezl_not_taken:
2964 add PC, 0x4 ; PC := PC + 4
2965 jmp _end_cycle
2966 ;-----------------------------------------------------------------------------
2967
2968 ;-----------------------------------------------------------------------------
2969 ; BGTZL - Branch on Greater Than Zero Likely.
2970 ; Test a register, then do a PC-relative conditional branch;
2971 ; execute the delay slot only if the branch is taken.
2972 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2973 ; added to the address of the instruction following the branch (not the branch
2974 ; itself), in the branch delay slot, to form a PC-relative effective target
2975 ; address. If the contents of rS are greater than zero (sign bit is 0 but
2976 ; value not zero), branch to the effective target address after the
2977 ; instruction in the delay slot is executed. If the branch is not taken, the
2978 ; instruction in the delay slot is not executed.
2979 ; Operation: If rS > 0 then branch_likely
2980 ; Syntax: bgtzl $s, offset
2981 ; Encoding: 0101 11ss sss0 0000 iiii iiii iiii iiii
2982 ;-----------------------------------------------------------------------------
2983 align GRAIN, db 0x90
2984 _i_bgtzl:
2985 IType_S_Only ; load only rS Field just now
2986 cmp R(rS), 0 ; CMP(Regs[rS], 0)
2987 jng _i_bgtzl_not_taken ; If !(Regs[rS] > 0) then NotTaken
2988 ; Taken:
2989 IType_I_Only ; load only Imm Field just now
2990 SX18_4N Imm ; Sign Extend Imm * 4
2991 mov nPC, PC ; nPC := PC
2992 add nPC, 0x4 ; nPC := nPC + 4
2993 add nPC, Imm ; nPC := nPC + Offset
2994 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2995 jmp _end_cycle
2996 ; Not Taken:
2997 _i_bgtzl_not_taken:
2998 add PC, 0x4 ; PC := PC + 4
2999 jmp _end_cycle
3000 ;-----------------------------------------------------------------------------
3001
3002 ;-----------------------------------------------------------------------------
3003 ; MUL - Multiply Word to Register.
3004 ; The 32-bit word value in rS is multiplied by the 32-bit value in rT,
3005 ; treating both operands as signed values, to produce a 64-bit result.
3006 ; The least significant 32 bits of the product are written to rD.
3007 ; The contents of HI and LO are UNPREDICTABLE after the operation.
3008 ; No arithmetic exception occurs under any circumstances.
3009 ; Syntax: mul $d, $s, $t
3010 ; Encoding: 0111 00ss ssst tttt dddd d000 0000 0010
3011 ;-----------------------------------------------------------------------------
3012 ; TODO: untested
3013 align GRAIN, db 0x90
3014 _i_mul:
3015 RType ; load rD, rS, rT Fields
3016 mov TMP, R(rT) ; TMP := Regs[rT]
3017 imul TMP, R(rS) ; TMP := TMP * Regs[rS] (Bottom 32 bits)
3018 Wr_Reg rD, TMP ; Regs[rD] := Bottom 32 bits of prod
3019 jmp _end_cycle
3020 ;-----------------------------------------------------------------------------
3021
3022 ;-----------------------------------------------------------------------------
3023 ; LB -- Load Byte.
3024 ; A byte is loaded into a register from the specified address.
3025 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3026 ; Syntax: lb $t, offset($s)
3027 ; Encoding: 1000 00ss ssst tttt iiii iiii iiii iiii
3028 ;-----------------------------------------------------------------------------
3029 align GRAIN, db 0x90
3030 _i_lb:
3031 IType ; Load Imm, rS, rT Fields
3032 SX16 Imm ; Sign-extend the Imm offset
3033 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3034 call _Virt_Read_Byte ; AL := Virt_Read_Byte(EAX)
3035 shl eax, 24 ; Shift left for sign-extension:
3036 sar eax, 24 ; Shift back right, dragging sign bit:
3037 Wr_Reg rT, EAX ; Regs[rT] := EAX
3038 jmp _end_cycle
3039 ;-----------------------------------------------------------------------------
3040
3041 ;-----------------------------------------------------------------------------
3042 ; LH - Load Halfword.
3043 ; Load a halfword from memory as a signed value.
3044 ; The contents of the 16-bit halfword at the memory location specified by the
3045 ; aligned effective address are fetched, sign-extended, and placed in rT.
3046 ; The 16-bit signed offset is added to the contents of rS to form the
3047 ; effective address. The effective address must be naturally-aligned.
3048 ; If the least-significant bit of the address is non-zero, an Address
3049 ; Error exception occurs
3050 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3051 ; Syntax: lh $t, offset($s)
3052 ; Encoding: 1000 01ss ssst tttt iiii iiii iiii iiii
3053 ;-----------------------------------------------------------------------------
3054 ; NOTE: LHU is exactly same thing as LH, but without sign-extend.
3055 align GRAIN, db 0x90
3056 _i_lh:
3057 IType ; Load Imm, rS, rT Fields
3058 SX16 Imm ; Sign-extend the Imm offset
3059 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3060 ;; rS (ecx) is not needed any more, can be reused
3061 bt Imm, 0 ; Get low bit of vAddr
3062 jnc _i_lh_aligned_ok ; If zero, vAddr was properly aligned;
3063 SetEXC EXC_AdEL ; If vAddr was NOT properly aligned:
3064 jmp _Handle_Exception ; Go straight to exception handler.
3065 _i_lh_aligned_ok: ; Load is to proceed normally:
3066 mov ecx, Imm ; Save vAddr to ECX
3067 xor TMP, TMP ; Clear TMP, where we will put the HW
3068 %ifdef LITTLE_ENDIAN
3069 ;; Read the low byte of the HW first:
3070 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr)
3071 mov TMP, eax ; TMP := eax (save the low byte)
3072 ;; Now read the high byte:
3073 mov eax, ecx ; Restore the original saved vAddr
3074 or eax, 1 ; Will read vAddr + 1
3075 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3076 %else
3077 or Imm, 1 ; First, read vAddr + 1 :
3078 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3079 mov TMP, eax ; TMP := eax (save low byte)
3080 mov eax, ecx ; Restore the original saved vAddr
3081 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr)
3082 %endif
3083 shl eax, 8 ; eax := eax << 8
3084 or eax, TMP ; eax := eax | TMP (high | low)
3085 shl eax, 16 ; left shift eax to put the HW on top
3086 sar eax, 16 ; right shift it back, to sign-extend.
3087 Wr_Reg rT, eax ; Regs[rT] := EAX (write back result)
3088 jmp _end_cycle
3089 ;-----------------------------------------------------------------------------
3090
3091 ;-----------------------------------------------------------------------------
3092 ; LWL - Load Word Left.
3093 ; Load the most-significant part of a word as a signed value from an unaligned
3094 ; memory address.
3095 ; Operation: $t = $t MERGE MEM[$s + offset]; advance_pc(4);
3096 ; Syntax: lwl $t, offset($s)
3097 ; Encoding: 1000 10ss ssst tttt iiii iiii iiii iiii
3098 ;-----------------------------------------------------------------------------
3099 align GRAIN, db 0x90
3100 _i_lwl:
3101 IType ; Load Imm, rS, rT Fields
3102 SX16 Imm ; Sign-extend the Imm offset
3103 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3104 ;; rS (ecx) is not needed any more, can be reused
3105 mov TMP, R(rT) ; TMP := Regs[rT] (old reg value)
3106 mov AUX, Imm ; Save the original unaligned address
3107 and Imm, ~(0x3) ; Clear bottom two bits of address
3108 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3109 ;; Proceed with write. EAX : old word, TMP : new word, ebx : still rT
3110 mov ecx, AUX ; ecx := original unaligned address
3111 and ecx, 0x3 ; keep only bottom two bits of it
3112 shl ecx, 3 ; ecx := ecx (8 * (addr[0..2]))
3113 shl eax, cl ; left shift eax (orig word) by above
3114 xor ecx, 24 ; ecx := 24 - ecx
3115 mov AUX, 0xFFFFFF ; AUX := 0xFFFFFF
3116 shr AUX, cl ; AUX := AUX >> cl
3117 and TMP, AUX ; TMP := TMP & AUX
3118 or TMP, eax ; TMP := TMP | eax (the writeback value)
3119 Wr_Reg rT, TMP ; Regs[rT] := TMP (the writeback value)
3120 jmp _end_cycle
3121 ;-----------------------------------------------------------------------------
3122
3123 ;-----------------------------------------------------------------------------
3124 ; LW -- Load Word.
3125 ; The contents of the 32-bit word at the memory location specified by the
3126 ; aligned effective address are fetched, signextended to the register length
3127 ; if necessary, and placed in register rT. The 16-bit signed offset is added
3128 ; to the contents of the base to form the effective address.
3129 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3130 ; Syntax: lw $t, offset($s)
3131 ; Encoding: 1000 11ss ssst tttt iiii iiii iiii iiii
3132 ;-----------------------------------------------------------------------------
3133 align GRAIN, db 0x90
3134 _i_lw:
3135 IType ; Load Imm, rS, rT Fields
3136 SX16 Imm ; Sign-extend the Imm offset
3137 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3138 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX)
3139 Wr_Reg rT, EAX ; Regs[rT] := EAX
3140 jmp _end_cycle
3141 ;-----------------------------------------------------------------------------
3142
3143 ;-----------------------------------------------------------------------------
3144 ; LBU - Load Byte Unsigned.
3145 ; Load a byte from memory as an unsigned value.
3146 ; The contents of the 8-bit byte at the memory location specified by the
3147 ; effective address are fetched, zero-extended, and placed in rT.
3148 ; The 16-bit signed offset is added to the contents of rS to form the
3149 ; effective address.
3150 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3151 ; Syntax: lbu $t, offset($s)
3152 ; Encoding: 1001 00ss ssst tttt iiii iiii iiii iiii
3153 ;-----------------------------------------------------------------------------
3154 align GRAIN, db 0x90
3155 _i_lbu:
3156 IType ; Load Imm, rS, rT Fields
3157 SX16 Imm ; Sign-extend the Imm offset
3158 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3159 call _Virt_Read_Byte ; AL := Virt_Read_Byte(EAX)
3160 Wr_Reg rT, EAX ; Regs[rT] := EAX
3161 jmp _end_cycle
3162 ;-----------------------------------------------------------------------------
3163
3164 ;-----------------------------------------------------------------------------
3165 ; LHU - Load Halfword Unsigned.
3166 ; Load a halfword from memory as an unsigned value.
3167 ; The contents of the 16-bit halfword at the memory location specified by the
3168 ; aligned effective address are fetched, zero-extended, and placed in reg rT.
3169 ; The 16-bit signed offset is added to the contents of register rS to form the
3170 ; effective address. The effective address must be naturally-aligned.
3171 ; If the least-significant bit of the address is non-zero,
3172 ; an Address Error exception occurs.
3173 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3174 ; Syntax: lhu $t, offset($s)
3175 ; Encoding: 1001 01ss ssst tttt iiii iiii iiii iiii
3176 ;-----------------------------------------------------------------------------
3177 ; NOTE: exactly same thing as LH, but WITHOUT sign-extend.
3178 align GRAIN, db 0x90
3179 _i_lhu:
3180 IType ; Load Imm, rS, rT Fields
3181 SX16 Imm ; Sign-extend the Imm offset
3182 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3183 ;; rS (ecx) is not needed any more, can be reused
3184 bt Imm, 0 ; Get low bit of vAddr
3185 jnc _i_lhu_aligned_ok ; If zero, vAddr was properly aligned;
3186 SetEXC EXC_AdEL ; If vAddr was NOT properly aligned:
3187 jmp _Handle_Exception ; Go straight to exception handler.
3188 _i_lhu_aligned_ok: ; Load is to proceed normally:
3189 mov ecx, Imm ; Save vAddr to ECX
3190 xor TMP, TMP ; Clear TMP, where we will put the HW
3191 %ifdef LITTLE_ENDIAN
3192 ;; Read the low byte of the HW first:
3193 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3194 mov TMP, eax ; TMP := eax (save the low byte)
3195 ;; Now read the high byte:
3196 mov eax, ecx ; Restore the original saved vAddr
3197 or eax, 1 ; Will read vAddr + 1
3198 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3199 %else
3200 or Imm, 1 ; First, read vAddr + 1 :
3201 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3202 mov TMP, eax ; TMP := eax (save low byte)
3203 mov eax, ecx ; Restore the original saved vAddr
3204 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr)
3205 %endif
3206 shl eax, 8 ; eax := eax << 8
3207 or eax, TMP ; eax := eax | TMP (high | low)
3208 Wr_Reg rT, eax ; Regs[rT] := EAX (write back result)
3209 jmp _end_cycle
3210 ;-----------------------------------------------------------------------------
3211
3212 ;-----------------------------------------------------------------------------
3213 ; LWL - Load Word Right.
3214 ; Load the least-significant part of a word from an unaligned memory address
3215 ; as a signed value. The 16-bit signed offset is added to the contents of rS
3216 ; to form an effective address (EffAddr). EffAddr is the address of the
3217 ; least-significant of 4 consecutive bytes forming a word (W) in memory
3218 ; starting at an arbitrary byte boundary. A part of W, the least-significant
3219 ; 1 to 4 bytes, is in the aligned word containing EffAddr. This part of W is
3220 ; loaded into the least-significant (right) part of the word in register rT.
3221 ; The remaining most-significant part of the word in register rT is unchanged.
3222 ; Executing both LWR and LWL, in either order, delivers a sign-extended word
3223 ; value in the destination register.
3224 ; Operation: $t = $t MERGE MEM[$s + offset]; advance_pc(4);
3225 ; Syntax: lwr $t, offset($s)
3226 ; Encoding: 1001 10ss ssst tttt iiii iiii iiii iiii
3227 ;-----------------------------------------------------------------------------
3228 align GRAIN, db 0x90
3229 _i_lwr:
3230 IType ; Load Imm, rS, rT Fields
3231 SX16 Imm ; Sign-extend the Imm offset
3232 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3233 ;; rS (ecx) is not needed any more, can be reused
3234 mov TMP, R(rT) ; TMP := Regs[rT] (value to write)
3235 mov AUX, Imm ; Save the original unaligned address
3236 and Imm, ~(0x3) ; Clear bottom two bits of address
3237 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3238 ;; Proceed with write. EAX : old word, TMP : new word, ebx : still rT
3239 mov ecx, AUX ; ecx := original unaligned address
3240 and ecx, 0x3 ; keep only bottom two bits of it
3241 shl ecx, 3 ; ecx := ecx (8 * (addr[0..2]))
3242 mov AUX, 0xFFFFFF00 ; AUX := 0xFFFFFF00
3243 shl AUX, cl ; AUX := AUX << cl
3244 and TMP, AUX ; TMP := TMP & AUX
3245 xor ecx, 24 ; ecx := 24 - ecx
3246 shr eax, cl ; right shift eax (orig word) by above
3247 or TMP, eax ; TMP := TMP | eax (the writeback value)
3248 Wr_Reg rT, TMP ; Regs[rT] := TMP (the writeback value)
3249 jmp _end_cycle
3250 ;-----------------------------------------------------------------------------
3251
3252 ;-----------------------------------------------------------------------------
3253 ; SB -- Store Byte.
3254 ; The least significant byte of $t is stored at the specified address.
3255 ; Operation: MEM[$s + offset] = (0xff & $t); advance_pc(4);
3256 ; Syntax: sb $t, offset($s)
3257 ; Encoding: 1010 00ss ssst tttt iiii iiii iiii iiii
3258 ;-----------------------------------------------------------------------------
3259 align GRAIN, db 0x90
3260 _i_sb:
3261 IType ; Load Imm, rS, rT Fields
3262 SX16 Imm ; Sign-extend the Imm offset
3263 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3264 mov TMP, R(rT) ; TMP (EDX) := Regs[rT]
3265 and TMP, 0xFF ; Keep only low byte of TMP
3266 call _Virt_Write_Byte ; Virt_Write_Byte(EAX, DL)
3267 jmp _end_cycle
3268 ;-----------------------------------------------------------------------------
3269
3270 ;-----------------------------------------------------------------------------
3271 ; SH - Store Halfword.
3272 ; Store a halfword to memory. The least-significant 16-bit halfword of
3273 ; register rT is stored in memory at the location specified by the aligned
3274 ; effective address. The 16-bit signed offset is added to the contents of rS
3275 ; to form the effective address.
3276 ; The effective address must be naturally-aligned. If the least-significant
3277 ; bit of the address is non-zero, an Address Error exception occurs.
3278 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3279 ; Syntax: sh $t, offset($s)
3280 ; Encoding: 1010 01ss ssst tttt iiii iiii iiii iiii
3281 ;-----------------------------------------------------------------------------
3282 align GRAIN, db 0x90
3283 _i_sh:
3284 IType ; Load Imm, rS, rT Fields
3285 SX16 Imm ; Sign-extend the Imm offset
3286 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3287 bt Imm, 0 ; Get low bit of vAddr
3288 jnc _i_sh_aligned_ok ; If zero, vAddr was properly aligned;
3289 SetEXC EXC_AdES ; If vAddr was NOT properly aligned:
3290 jmp _Handle_Exception ; Go straight to exception handler.
3291 _i_sh_aligned_ok:
3292 mov AUX, Imm ; Save Imm (vAddr) to AUX
3293 ;; rS (ecx) is not needed any more, can be reused
3294 mov ecx, R(rT) ; ecx := Regs[rT] (HW to be written)
3295 mov TMP, ecx ; TMP := ecx
3296 %ifdef LITTLE_ENDIAN
3297 and TMP, 0xFF ; isolate low byte
3298 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr, DL)
3299 mov TMP, ecx ; TMP := the whole HW again
3300 and TMP, 0xFF00 ; isolate high byte
3301 shr TMP, 8 ; TMP := TMP >> 8 (get high byte)
3302 %else ;; Big-Endian
3303 shr TMP, 8 ; TMP := TMP >> 8 (get high byte)
3304 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr, DL)
3305 mov TMP, ecx ; TMP := ecx again, now for low byte
3306 and TMP, 0xFF ; isolate low byte
3307 %endif
3308 mov eax, AUX ; restore vAddr from AUX
3309 or eax, 1 ; set bottom bit, for vAddr + 1
3310 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr + 1, DL)
3311 jmp _end_cycle
3312 ;-----------------------------------------------------------------------------
3313
3314 ;-----------------------------------------------------------------------------
3315 ; SWL - Store Word Left.
3316 ; Store the most-significant part of a word to an unaligned memory address.
3317 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3318 ; Syntax: swl $t, offset($s)
3319 ; Encoding: 1010 10ss ssst tttt iiii iiii iiii iiii
3320 ;-----------------------------------------------------------------------------
3321 align GRAIN, db 0x90
3322 _i_swl:
3323 IType ; Load Imm, rS, rT Fields
3324 SX16 Imm ; Sign-extend the Imm offset
3325 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3326 ;; rS (ecx) is not needed any more, can be reused
3327 mov TMP, R(rT) ; TMP := Regs[rT] (old reg value)
3328 ;; rT (ebx) is not needed any more, can be reused
3329 mov AUX, Imm ; Save the original unaligned address
3330 and Imm, ~(0x3) ; Clear bottom two bits of address
3331 mov ebx, Imm ; Save the aligned address for writeback
3332 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3333 ;; Proceed with write. EAX : old word, TMP : new word, ebx : WB addr.
3334 mov ecx, AUX ; ecx := original unaligned address
3335 and ecx, 0x3 ; keep only bottom two bits
3336 shl ecx, 3 ; ecx := ecx (8 * (addr[0..2]))
3337 shr TMP, cl ; right shift TMP by above
3338 xor ecx, 24 ; ecx := 24 - ecx
3339 mov AUX, 0xFFFFFF00 ; AUX := 0xFFFFFF00
3340 shl AUX, cl ; AUX := AUX << cl
3341 and eax, AUX ; eax := eax & AUX
3342 or TMP, eax ; TMP := TMP | eax (the writeback value)
3343 mov eax, ebx ; restore aligned address for writeback
3344 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3345 jmp _end_cycle
3346 ;-----------------------------------------------------------------------------
3347
3348 ;-----------------------------------------------------------------------------
3349 ; SW -- Store Word.
3350 ; The contents of $t is stored at the specified address.
3351 ; The effective address must be naturally-aligned.
3352 ; If either of the 2 least-significant bits of the address is non-zero,
3353 ; an Address Error exception occurs.
3354 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3355 ; Syntax: sw $t, offset($s)
3356 ; Encoding: 1010 11ss ssst tttt iiii iiii iiii iiii
3357 ;-----------------------------------------------------------------------------
3358 align GRAIN, db 0x90
3359 _i_sw:
3360 IType ; Load Imm, rS, rT Fields
3361 SX16 Imm ; Sign-extend the Imm offset
3362 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3363 mov TMP, R(rT) ; TMP := Regs[rT]
3364 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3365 jmp _end_cycle
3366 ;-----------------------------------------------------------------------------
3367
3368 ;-----------------------------------------------------------------------------
3369 ; SWR - Store Word Right.
3370 ; Store the least-significant part of a word to an unaligned memory address.
3371 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3372 ; Syntax: swr $t, offset($s)
3373 ; Encoding: 1011 10ss ssst tttt iiii iiii iiii iiii
3374 ;-----------------------------------------------------------------------------
3375 align GRAIN, db 0x90
3376 _i_swr:
3377 IType ; Load Imm, rS, rT Fields
3378 SX16 Imm ; Sign-extend the Imm offset
3379 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3380 ;; rS (ecx) is not needed any more, can be reused
3381 mov TMP, R(rT) ; TMP := Regs[rT] (value to write)
3382 ;; rT (ebx) is not needed any more, can be reused
3383 mov AUX, Imm ; Save the original unaligned address
3384 and Imm, ~(0x3) ; Clear bottom two bits of address
3385 mov ebx, Imm ; Save the aligned address for writeback
3386 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3387 ;; Proceed with write. EAX : old word, TMP : new word, ebx : WB addr.
3388 mov ecx, AUX ; ecx := original unaligned address
3389 and ecx, 0x3 ; keep only bottom two bits
3390 shl ecx, 3 ; ecx := ecx * 8
3391 mov AUX, 0xFFFFFF ; AUX := 0xFFFFFF
3392 shr AUX, cl ; AUX := AUX >> cl
3393 and eax, AUX ; eax := eax & AUX
3394 xor ecx, 24 ; ecx := 24 - ecx (24 - 8 * (addr[0..2]))
3395 shl TMP, cl ; left shift TMP (value to write) by above
3396 or TMP, eax ; TMP := TMP | eax (the writeback value)
3397 mov eax, ebx ; restore aligned address for writeback
3398 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3399 jmp _end_cycle
3400 ;-----------------------------------------------------------------------------
3401
3402 ;-----------------------------------------------------------------------------
3403 ; CACHE.
3404 ; Operation: This is a NOP in this emulator.
3405 ; Syntax: cache $t, offset($s)
3406 ; Encoding: 1011 11ss ssst tttt iiii iiii iiii iiii
3407 ; PRIVILEGED (permitted in Kernel Mode only.)
3408 ;-----------------------------------------------------------------------------
3409 align GRAIN, db 0x90
3410 _i_cache:
3411 ; no fields
3412 PRIVILEGED ; Permitted in Kernel Mode only.
3413 jmp _end_cycle
3414 ;-----------------------------------------------------------------------------
3415
3416 ;-----------------------------------------------------------------------------
3417 ; LL - Load Linked Word.
3418 ; Load a word from memory for an atomic read-modify-write.
3419 ; The contents of the 32-bit word at the memory location specified by the
3420 ; aligned effective address are fetched and written into register rT.
3421 ; The 16-bit signed offset is added to the contents of rS to form
3422 ; an effective address.
3423 ; Operation: $t = MEM[$s + offset]; llbit = 1; advance_pc(4);
3424 ; Syntax: ll $t, offset($s)
3425 ; Encoding: 1100 00ss ssst tttt iiii iiii iiii iiii
3426 ;-----------------------------------------------------------------------------
3427 align GRAIN, db 0x90
3428 _i_ll:
3429 IType ; Load Imm, rS, rT Fields
3430 SX16 Imm ; Sign-extend the Imm offset
3431 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3432 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX)
3433 Wr_Reg rT, EAX ; Regs[rT] := EAX
3434 Flg_On LL_Bit ; Set the LL_Bit Flag
3435 jmp _end_cycle
3436 ;-----------------------------------------------------------------------------
3437
3438 ;-----------------------------------------------------------------------------
3439 ; PREF - Prefetch.
3440 ; Operation: This is a NOP in this emulator.
3441 ; Syntax: pref $t, offset($s)
3442 ; Encoding: 1100 11ss ssst tttt iiii iiii iiii iiii
3443 ;-----------------------------------------------------------------------------
3444 align GRAIN, db 0x90
3445 _i_pref:
3446 ; no fields
3447 jmp _end_cycle
3448 ;-----------------------------------------------------------------------------
3449
3450 ;-----------------------------------------------------------------------------
3451 ; SC - Store Conditional Word.
3452 ; Store a word to memory to complete an atomic read-modify-write.
3453 ; The 32-bit word in rT is conditionally stored in memory at the location
3454 ; specified by the aligned effective address.
3455 ; The 16-bit signed offset is added to the contents of rS to form an
3456 ; effective address
3457 ; Operation: if llbit == 1 then: MEM[$s + offset] = $t; rt = 1; advance_pc(4);
3458 ; else: rt = 0; advance_pc(4);
3459 ; Syntax: sc $t, offset($s)
3460 ; Encoding: 1110 00ss ssst tttt iiii iiii iiii iiii
3461 ;-----------------------------------------------------------------------------
3462 align GRAIN, db 0x90
3463 _i_sc:
3464 IType ; Load Imm, rS, rT Fields
3465 Flg_Get LL_Bit ; CF := LL_Bit
3466 jnc _i_sc_not_taken ; If LL_Bit = 0, then do not store; else:
3467 SX16 Imm ; Sign-extend the Imm offset
3468 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3469 mov TMP, R(rT) ; TMP := Regs[rT]
3470 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3471 mov R(rT), 1 ; Regs[rT] := 1 ('yes, stored word')
3472 jmp _i_sc_done ; Done.
3473 _i_sc_not_taken:
3474 mov R(rT), 0 ; Regs[rT] := 0 ('no, did not store')
3475 _i_sc_done:
3476 jmp _end_cycle
3477 ;-----------------------------------------------------------------------------
-
+ C5AFA1184E847BA45411669A68D1CC0F62A2BACB17155541F525A70D4EDEFD9A62789675F30C1EB79621D8737674FE39BA7A5D913D30FE18E8B785F3CF48276D
m/mipsinst/m_instrs.asm
(0 . 0)(1 . 557)
3482 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3483 ;; ;;
3484 ;; This file is part of 'M', a MIPS system emulator. ;;
3485 ;; ;;
3486 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
3487 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
3488 ;; ;;
3489 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
3490 ;; distribute this software ; Should you use this software for any purpose, ;;
3491 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
3492 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
3493 ;; continue doing so for the indefinite future. In any case, please ;;
3494 ;; always : read and understand any software ; verify any PGP signatures ;;
3495 ;; that you use - for any purpose. ;;
3496 ;; ;;
3497 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
3498 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3499
3500 ;; TODO: Tests!!!
3501
3502 ;-----------------------------------------------------------------------------
3503 section .rodata
3504 align GRAIN, db 0x90
3505 _M_Table:
3506 A32 _bad ; 0x00 : UNDEFINED
3507 A32 _bad ; 0x01 : UNDEFINED
3508 A32 _m_tlbwi ; 0x02 : tlbwi (01000010000000000000000000000010)
3509 A32 _bad ; 0x03 : UNDEFINED
3510 A32 _bad ; 0x04 : UNDEFINED
3511 A32 _bad ; 0x05 : UNDEFINED
3512 A32 _m_tlbwr ; 0x06 : tlbwr (01000010000000000000000000000110)
3513 A32 _bad ; 0x07 : UNDEFINED
3514 A32 _m_tlbp ; 0x08 : tlbp (01000010000000000000000000001000)
3515 A32 _bad ; 0x09 : UNDEFINED
3516 A32 _bad ; 0x0a : UNDEFINED
3517 A32 _bad ; 0x0b : UNDEFINED
3518 A32 _bad ; 0x0c : UNDEFINED
3519 A32 _bad ; 0x0d : UNDEFINED
3520 A32 _bad ; 0x0e : UNDEFINED
3521 A32 _bad ; 0x0f : UNDEFINED
3522 A32 _bad ; 0x10 : UNDEFINED
3523 A32 _bad ; 0x11 : UNDEFINED
3524 A32 _bad ; 0x12 : UNDEFINED
3525 A32 _bad ; 0x13 : UNDEFINED
3526 A32 _bad ; 0x14 : UNDEFINED
3527 A32 _bad ; 0x15 : UNDEFINED
3528 A32 _bad ; 0x16 : UNDEFINED
3529 A32 _bad ; 0x17 : UNDEFINED
3530 A32 _m_eret ; 0x18 : eret (01000010000000000000000000011000)
3531 A32 _bad ; 0x19 : UNDEFINED
3532 A32 _bad ; 0x1a : UNDEFINED
3533 A32 _bad ; 0x1b : UNDEFINED
3534 A32 _bad ; 0x1c : UNDEFINED
3535 A32 _bad ; 0x1d : UNDEFINED
3536 A32 _bad ; 0x1e : UNDEFINED
3537 A32 _bad ; 0x1f : UNDEFINED
3538 ;-----------------------------------------------------------------------------
3539
3540 section .text
3541
3542 ;-----------------------------------------------------------------------
3543 ; 'M-Type' Instructions (tlbwi, tlbwr, tlbp, eret, mfc0, mtc0, wait) : |
3544 ;-----------------------------------------------------------------------
3545
3546 ;-----------------------------------------------------------------------------
3547 ; TLBWI - Write Indexed TLB Entry.
3548 ; Write a TLB entry indexed by the Index register.
3549 ; The TLB entry pointed to by the Index register is written from the contents
3550 ; of the EntryHi, EntryLo0, EntryLo1, and PageMask registers.
3551 ; Syntax: tlbwi
3552 ; Encoding: 0100 0010 0000 0000 0000 0000 0000 0010
3553 ; PRIVILEGED (permitted in Kernel Mode only.)
3554 ;-----------------------------------------------------------------------------
3555 align GRAIN, db 0x90
3556 _m_tlbwi:
3557 ; no fields
3558 mov AUX, Sr(CP0_Index) ; Get CP0_Index register
3559 call _write_tlb_entry ; Write the indexed TLB entry.
3560 jmp _end_cycle
3561 ;-----------------------------------------------------------------------------
3562
3563 ;-----------------------------------------------------------------------------
3564 ; TLBWR - Write Random TLB Entry.
3565 ; Write a TLB entry indexed by the Random register.
3566 ; The TLB entry pointed to by the Random register is written from the contents
3567 ; of the EntryHi, EntryLo0, EntryLo1, and PageMask registers.
3568 ; Syntax: tlbwr
3569 ; Encoding: 0100 0010 0000 0000 0000 0000 0000 0110
3570 ; PRIVILEGED (permitted in Kernel Mode only.)
3571 ;-----------------------------------------------------------------------------
3572 align GRAIN, db 0x90
3573 _m_tlbwr:
3574 ; no fields
3575 mov ecx, Sr(CP0_Wired) ; ecx := CP0_Wired
3576 mov ebx, TLB_ENTRIES_COUNT ; ebx := #tlbentries
3577 sub ebx, ecx ; ebx := #tlbentries - Wired
3578 mov edx, 0 ; edx (upper half of dividend) := 0
3579 mov eax, CP0_Count ; eax (lower half of divident) := cnt
3580 div ebx ; edx:eax / ebx
3581 add edx, ecx ; edx (remainder) := edx + wired
3582 mov AUX, edx ; make edx the index for tlb write
3583 call _write_tlb_entry ; Write the indexed TLB entry.
3584 jmp _end_cycle
3585 ;-----------------------------------------------------------------------------
3586
3587 ;-----------------------------------------------------------------------------
3588 ; TLBP - Probe TLB for Matching Entry.
3589 ; Find a matching entry in the TLB.
3590 ; The Index register is loaded with the address of the TLB entry whose
3591 ; contents match the contents of the EntryHi register. If no TLB entry
3592 ; matches, the high-order bit of the Index register is set.
3593 ; Syntax: tlbp
3594 ; Encoding: 0100 0010 0000 0000 0000 0000 0000 1000
3595 ; PRIVILEGED (permitted in Kernel Mode only.)
3596 ;-----------------------------------------------------------------------------
3597 align GRAIN, db 0x90
3598 _m_tlbp:
3599 ; no fields
3600 mov Sr(CP0_Index), 0x80000000 ; CP0_Index := 0x80000000
3601 ;; Get the active ASID:
3602 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
3603 mov ecx, edx ; ecx := edx
3604 and edx, 0xFF ; edx := edx & 0xFF (get current ASID)
3605 ;; Get the desired tag:
3606 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
3607 shr ecx, 13 ; ecx := ecx >> 13 (current Tag)
3608 ;; For each slot in table (0 .. 15), attempt lookup
3609 xor AUX, AUX ; Start with the 0-th entry in table
3610 _m_tlbp_lookup_entry:
3611 mov eax, TLB_E(AUX) ; eax := current TLB entry
3612 mov ebx, eax ; ebx := eax
3613 and ebx, TLB_VPN2_Mask ; get VPN2 of this entry
3614 cmp ebx, ecx ; cmp(entry.VPN2, vAddr.tag)
3615 jne _m_tlbp_lookup_nope ; if entry.VPN2 != vAddr.tag: no match
3616 bt eax, TLB_G ; is entry.G = 1?
3617 jc _m_tlbp_lookup_match ; then match.
3618 shr eax, TLB_ASID_Shift ; eax := eax >> TLB_ASID_Shift
3619 and eax, TLB_ASID_Mask ; eax := entry.ASID
3620 cmp eax, edx ; entry.ASID = current ASID ?
3621 jne _m_tlbp_lookup_nope ; if neither G=1 nor ASID match.
3622 ;; otherwise:
3623 _m_tlbp_lookup_match: ; TLB Match:
3624 mov Sr(CP0_Index), AUX ; Save the index
3625 jmp _end_cycle ; Fin.
3626 _m_tlbp_lookup_nope: ; try next one in the table, if any
3627 inc AUX ; index := index + 1
3628 cmp AUX, TLB_ENTRIES_COUNT ; see if still in range 0 .. n-1
3629 jb _m_tlbp_lookup_entry ; if in range, go to next entry
3630 ;; if we found nothing, we end up with CP0_Index = 0x80000000
3631 jmp _end_cycle ; Fin.
3632 ;-----------------------------------------------------------------------------
3633
3634 ;-----------------------------------------------------------------------------
3635 ; ERET - Exception Return.
3636 ; Return from interrupt, exception, or error trap.
3637 ; Syntax: eret
3638 ; Encoding: 0100 0010 0000 0000 0000 0000 0001 1000
3639 ; PRIVILEGED (permitted in Kernel Mode only.)
3640 ;;-----------------------------------------------------------------------------
3641 align GRAIN, db 0x90
3642 _m_eret:
3643 ; no fields
3644 Flg_Get InDelaySlot ; CF := whether we are in delay slot
3645 jc _m_eret_abort ; ... if so, abort this instruction; else:
3646 ;; proceed:
3647 Flg_Off LL_Bit ; Clear the LL_Bit Flag
3648 btr CP0_Status, CP0St_ERL ; CF := CP0St_ERL Flag, and clear it
3649 jnc _m_eret_erl_false ; If ERL was not set, do erl_false; else:
3650 _m_eret_erl_true:
3651 mov PC, Sr(CP0_ErrorEpc) ; PC := CP0_ErrorEpc
3652 jmp _m_eret_done ; Done with this case
3653 _m_eret_erl_false:
3654 mov PC, Sr(CP0_Epc) ; PC := CP0_Epc
3655 btr CP0_Status, CP0St_EXL ; Clear the EXL Flag
3656 _m_eret_done:
3657 sub PC, 0x4 ; Counteract the usual PC = PC + 4
3658 _m_eret_abort:
3659 jmp _end_cycle
3660 ;-----------------------------------------------------------------------------
3661
3662 ;-----------------------------------------------------------------------------
3663 ; MFC0 - Move from Coprocessor 0.
3664 ; Move the contents of a coprocessor 0 register to a general register.
3665 ; The contents of the coprocessor 0 register specified by the combination of
3666 ; rd and sel (q) are loaded into general register rt. Note that not all
3667 ; coprocessor 0 registers support the sel field. In those instances, the sel
3668 ; field must be zero.
3669 ; Operation: $t = CPR[0, rD, q]
3670 ; Syntax: mfc0 $t, $d, q
3671 ; Encoding: 0100 0000 000t tttt dddd d000 0000 0qqq
3672 ; PRIVILEGED (permitted in Kernel Mode only.)
3673 ;-----------------------------------------------------------------------------
3674 align GRAIN, db 0x90
3675 _m_mfc0:
3676 CPType ; Load Q, rD, rT (ecx, eax, ebx)
3677 JTABLE eax, _MFC0_Table ; Dispatch on rD via MFC0 Table.
3678 ;; We continue in _mfc0_rXX where XX is rD.
3679 ;-----------------------------------------------------------------------------
3680
3681 ;-----------------------------------------------------------------------------
3682 ; MFC0 Cases. Parameters: Q (ecx), rD (eax), rT (ebx)
3683 ;-----------------------------------------------------------------------------
3684 _mfc0_r00: ; 0x00
3685 test ecx, ecx ; Sel != 0 ?
3686 jnz _mfc0_unknown ; ... then unknown; else:
3687 mov TMP, Sr(CP0_Index) ; return CP0_Index
3688 jmp _mfc0_writeback ; Done
3689 ;-----------------------------------------------------------------------------
3690 _mfc0_r01: ; 0x01
3691 jmp _mfc0_unknown
3692 ;-----------------------------------------------------------------------------
3693 _mfc0_r02: ; 0x02
3694 mov TMP, Sr(CP0_EntryLo0) ; return CP0_EntryLo0
3695 jmp _mfc0_writeback ; Done
3696 ;-----------------------------------------------------------------------------
3697 _mfc0_r03: ; 0x03
3698 mov TMP, Sr(CP0_EntryLo1) ; return CP0_EntryLo1
3699 jmp _mfc0_writeback ; Done
3700 ;-----------------------------------------------------------------------------
3701 _mfc0_r04: ; 0x04
3702 test ecx, ecx ; Sel != 0 ?
3703 jnz _mfc0_unknown ; ... then unknown; else:
3704 mov TMP, Sr(CP0_Context) ; return CP0_Context
3705 jmp _mfc0_writeback ; Done
3706 ;-----------------------------------------------------------------------------
3707 _mfc0_r05: ; 0x05
3708 test ecx, ecx ; Sel != 0 ?
3709 jnz _mfc0_unknown ; ... then unknown; else:
3710 mov TMP, Sr(CP0_PageMask) ; return CP0_PageMask
3711 jmp _mfc0_writeback ; Done
3712 ;-----------------------------------------------------------------------------
3713 _mfc0_r06: ; 0x06
3714 test ecx, ecx ; Sel != 0 ?
3715 jnz _mfc0_unknown ; ... then unknown; else:
3716 mov TMP, Sr(CP0_Wired) ; return CP0_Wired
3717 jmp _mfc0_writeback ; Done
3718 ;-----------------------------------------------------------------------------
3719 _mfc0_r07: ; 0x07
3720 jmp _mfc0_unknown
3721 ;-----------------------------------------------------------------------------
3722 _mfc0_r08: ; 0x08
3723 test ecx, ecx ; Sel != 0 ?
3724 jnz _mfc0_unknown ; ... then unknown; else:
3725 mov TMP, Sr(CP0_BadVAddr) ; return CP0_BadVAddr
3726 jmp _mfc0_writeback ; Done
3727 ;-----------------------------------------------------------------------------
3728 _mfc0_r09: ; 0x09
3729 test ecx, ecx ; Sel != 0 ?
3730 jnz _mfc0_unknown ; ... then unknown; else:
3731 mov TMP, CP0_Count ; return CP0_Count ('fast reg')
3732 jmp _mfc0_writeback ; Done
3733 ;-----------------------------------------------------------------------------
3734 _mfc0_r10: ; 0x0a
3735 test ecx, ecx ; Sel != 0 ?
3736 jnz _mfc0_unknown ; ... then unknown; else:
3737 mov TMP, Sr(CP0_EntryHi) ; return CP0_EntryHi
3738 jmp _mfc0_writeback ; Done
3739 ;-----------------------------------------------------------------------------
3740 _mfc0_r11: ; 0x0b
3741 test ecx, ecx ; Sel != 0 ?
3742 jnz _mfc0_unknown ; ... then unknown; else:
3743 mov TMP, CP0_Compare ; return CP0_Compare ('fast reg')
3744 jmp _mfc0_writeback ; Done
3745 ;-----------------------------------------------------------------------------
3746 _mfc0_r12: ; 0x0c
3747 test ecx, ecx ; Sel != 0 ?
3748 jnz _mfc0_unknown ; ... then unknown; else:
3749 mov TMP, CP0_Status ; return CP0_Status ('fast reg')
3750 jmp _mfc0_writeback ; Done
3751 ;-----------------------------------------------------------------------------
3752 _mfc0_r13: ; 0x0d
3753 test ecx, ecx ; Sel != 0 ?
3754 jnz _mfc0_unknown ; ... then unknown; else:
3755 mov TMP, CP0_Cause ; return CP0_Cause ('fast reg')
3756 jmp _mfc0_writeback ; Done
3757 ;-----------------------------------------------------------------------------
3758 _mfc0_r14: ; 0x0e
3759 test ecx, ecx ; Sel != 0 ?
3760 jnz _mfc0_unknown ; ... then unknown; else:
3761 mov TMP, Sr(CP0_Epc) ; return CP0_Epc
3762 jmp _mfc0_writeback ; Done
3763 ;-----------------------------------------------------------------------------
3764 _mfc0_r15: ; 0x0f
3765 mov TMP, 0x00018000 ; processor id (qemu 4kc)
3766 jmp _mfc0_writeback ; Done
3767 ;-----------------------------------------------------------------------------
3768 _mfc0_r16: ; 0x10
3769 cmp r_Q, 0 ; Is sel = 0?
3770 je _mfc0_r16_q_0 ; If sel = 0...
3771 cmp r_Q, 1 ; Is sel = 1?
3772 je _mfc0_r16_q_1 ; If sel = 1...
3773 jmp _mfc0_unknown ; Unknown sel
3774 _mfc0_r16_q_0:
3775 mov TMP, 0x80008082 ; return 0x80008082
3776 jmp _mfc0_writeback ; Done
3777 _mfc0_r16_q_1:
3778 mov TMP, 0x1e190c8a ; return 0x1e190c8a
3779 jmp _mfc0_writeback ; Done
3780 ;-----------------------------------------------------------------------------
3781 _mfc0_r17: ; 0x11
3782 jmp _mfc0_unknown
3783 ;-----------------------------------------------------------------------------
3784 _mfc0_r18: ; 0x12
3785 xor TMP, TMP ; TMP = 0
3786 jmp _mfc0_writeback ; Done
3787 ;-----------------------------------------------------------------------------
3788 _mfc0_r19: ; 0x13
3789 xor TMP, TMP ; TMP = 0
3790 jmp _mfc0_writeback ; Done
3791 ;-----------------------------------------------------------------------------
3792 _mfc0_r20: ; 0x14
3793 jmp _mfc0_unknown
3794 ;-----------------------------------------------------------------------------
3795 _mfc0_r21: ; 0x15
3796 jmp _mfc0_unknown
3797 ;-----------------------------------------------------------------------------
3798 _mfc0_r22: ; 0x16
3799 jmp _mfc0_unknown
3800 ;-----------------------------------------------------------------------------
3801 _mfc0_r23: ; 0x17
3802 jmp _mfc0_unknown
3803 ;-----------------------------------------------------------------------------
3804 _mfc0_r24: ; 0x18
3805 jmp _mfc0_unknown
3806 ;-----------------------------------------------------------------------------
3807 _mfc0_r25: ; 0x19
3808 jmp _mfc0_unknown
3809 ;-----------------------------------------------------------------------------
3810 _mfc0_r26: ; 0x1a
3811 jmp _mfc0_unknown
3812 ;-----------------------------------------------------------------------------
3813 _mfc0_r27: ; 0x1b
3814 jmp _mfc0_unknown
3815 ;-----------------------------------------------------------------------------
3816 _mfc0_r28: ; 0x1c
3817 jmp _mfc0_unknown
3818 ;-----------------------------------------------------------------------------
3819 _mfc0_r29: ; 0x1d
3820 jmp _mfc0_unknown
3821 ;-----------------------------------------------------------------------------
3822 _mfc0_r30: ; 0x1e
3823 jmp _mfc0_unknown
3824 ;-----------------------------------------------------------------------------
3825 _mfc0_r31: ; 0x1f
3826 jmp _mfc0_unknown
3827 ;-----------------------------------------------------------------------------
3828 _mfc0_writeback: ; Write result and go to next cycle
3829 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
3830 jmp _end_cycle ; Fin
3831 ;-----------------------------------------------------------------------------
3832 _mfc0_unknown:
3833 ; 'The results are UNDEFINED if coprocessor 0 does not contain a
3834 ; register as specified by rd and sel.'
3835 ACHTUNG "Unknown CP0 Reg Selector in MFC0!" ;; TODO: print detail
3836 jmp _end_cycle ; Do nothing, carry on.
3837 ;-----------------------------------------------------------------------------
3838
3839 ;-----------------------------------------------------------------------------
3840 ; MTC0 - Move to Coprocessor 0.
3841 ; Move the contents of a general register to a coprocessor 0 register.
3842 ; The contents of general register rt are loaded into the coprocessor 0
3843 ; register specified by the combination of rd and sel (q). Not all
3844 ; coprocessor 0 registers support the the sel field. In those instances, the
3845 ; sel field must be set to zero.
3846 ; Operation: CPR[0, rD, q] = $t
3847 ; Syntax: mfc0 $t, $d, q
3848 ; Encoding: 0100 0000 100t tttt dddd d000 0000 0qqq
3849 ; PRIVILEGED (permitted in Kernel Mode only.)
3850 ;-----------------------------------------------------------------------------
3851 align GRAIN, db 0x90
3852 _m_mtc0:
3853 CPType ; Load Q, rD, rT (ecx, eax, ebx)
3854 mov rT, R(rT) ; ebx := Regs[rT]
3855 JTABLE eax, _MTC0_Table ; Dispatch on rD via MTC0 Table.
3856 ;; We continue in _mtc0_rXX where XX is rD.
3857 ;-----------------------------------------------------------------------------
3858
3859 ;-----------------------------------------------------------------------------
3860 ; MTC0 Cases. Parameters: Q (ecx), rD (eax), Regs[rT] (ebx)
3861 ;-----------------------------------------------------------------------------
3862 _mtc0_r00: ; 0x00
3863 test ecx, ecx ; Sel != 0 ?
3864 jnz _mtc0_unknown ; ... then unknown; else:
3865 mov eax, Sr(CP0_Index) ; eax := CP0_Index
3866 and ebx, 0xF ; T := T & 0xF
3867 and eax, 0x80000000 ; eax := eax & 0x80000000
3868 or eax, ebx ; eax := eax | T
3869 mov Sr(CP0_Index), eax ; CP0_Index := eax
3870 jmp _end_cycle ; Done
3871 ;-----------------------------------------------------------------------------
3872 _mtc0_r01: ; 0x01
3873 jmp _mtc0_unknown
3874 ;-----------------------------------------------------------------------------
3875 _mtc0_r02: ; 0x02
3876 and ebx, 0x3FFFFFF ; T := T & 0x3FFFFFF
3877 mov Sr(CP0_EntryLo0), ebx ; CP0_EntryLo0 := T
3878 jmp _end_cycle ; Done
3879 ;-----------------------------------------------------------------------------
3880 _mtc0_r03: ; 0x03
3881 and ebx, 0x3FFFFFF ; T := T & 0x3FFFFFF
3882 mov Sr(CP0_EntryLo1), ebx ; CP0_EntryLo1 := T
3883 jmp _end_cycle ; Done
3884 ;-----------------------------------------------------------------------------
3885 _mtc0_r04: ; 0x04
3886 %define CONTEXTMASK 0xFF800000
3887 %define nCONTEXTMASK (0xFFFFFFFF ^ 0xFF800000)
3888 mov eax, Sr(CP0_Context) ; eax := CP0_Context
3889 and ebx, CONTEXTMASK ; T := T & CONTEXTMASK
3890 and eax, nCONTEXTMASK ; eax := eax & ~CONTEXTMASK
3891 or eax, ebx ; eax := eax | T
3892 mov Sr(CP0_Context), eax ; CP0_Context := eax
3893 jmp _end_cycle ; Done
3894 ;-----------------------------------------------------------------------------
3895 _mtc0_r05: ; 0x05
3896 test ecx, ecx ; Sel != 0 ?
3897 jnz _mtc0_unknown ; ... then unknown; else:
3898 test ebx, ebx ; T != 0 ?
3899 jnz _mtc0_r05_untest_pgmask ; If so, eggog
3900 and ebx, 0x1FFE000 ; T := T & 0x1FFE000
3901 mov Sr(CP0_PageMask), ebx ; CP0_PageMask := T
3902 jmp _end_cycle ; Done
3903 _mtc0_r05_untest_pgmask: ; Proper kernel won't do this. But if someone does:
3904 ACHTUNG "MTC0: Unsupported Page Mask!" ; maybe halt w/ sirens?
3905 jmp _end_cycle ; Let's continue (probably wedged...)
3906 ;-----------------------------------------------------------------------------
3907 _mtc0_r06: ; 0x06
3908 test ecx, ecx ; Sel != 0 ?
3909 jnz _mtc0_unknown ; ... then unknown; else:
3910 and ebx, 0xF ; T := T & 0xF
3911 mov Sr(CP0_Wired), ebx ; CP0_Wired := T
3912 jmp _end_cycle ; Done
3913 ;-----------------------------------------------------------------------------
3914 _mtc0_r07: ; 0x07
3915 jmp _mtc0_unknown
3916 ;-----------------------------------------------------------------------------
3917 _mtc0_r08: ; 0x08
3918 jmp _mtc0_unknown
3919 ;-----------------------------------------------------------------------------
3920 _mtc0_r09: ; 0x09
3921 test ecx, ecx ; Sel != 0 ?
3922 jnz _mtc0_unknown ; ... then unknown; else:
3923 mov CP0_Count, ebx ; CP0_Count := T ('fast reg')
3924 jmp _end_cycle ; Done
3925 ;-----------------------------------------------------------------------------
3926 _mtc0_r10: ; 0x0a
3927 test ecx, ecx ; Sel != 0 ?
3928 jnz _mtc0_unknown ; ... then unknown; else:
3929 and ebx, ~0x1F00 ; T := T & ~0x1F00
3930 mov Sr(CP0_EntryHi), ebx ; CP0_EntryHi := T
3931 jmp _end_cycle ; Done
3932 ;-----------------------------------------------------------------------------
3933 _mtc0_r11: ; 0x0b
3934 test ecx, ecx ; Sel != 0 ?
3935 jnz _mtc0_unknown ; ... then unknown; else:
3936 ClrIRQ TIMER_IRQ ; Clear MIPS Timer IRQ
3937 mov CP0_Compare, ebx ; CP0_Compare := T ('fast reg')
3938 jmp _end_cycle ; Done
3939 ;-----------------------------------------------------------------------------
3940 _mtc0_r12: ; 0x0c
3941 test ecx, ecx ; Sel != 0 ?
3942 jnz _mtc0_unknown ; ... then unknown; else:
3943 %define STATUSMASK 0x7D7CFF17
3944 mov eax, CP0_Status ; eax := CP0_Status
3945 and ebx, STATUSMASK ; T := T & STATUSMASK
3946 and eax, ~STATUSMASK ; eax := eax & ~STATUSMASK
3947 or eax, ebx ; eax := eax | T
3948 mov CP0_Status, eax ; CP0_Status := eax
3949 jmp _end_cycle ; Done
3950 ;-----------------------------------------------------------------------------
3951 _mtc0_r13: ; 0x0d
3952 test ecx, ecx ; Sel != 0 ?
3953 jnz _mtc0_unknown ; ... then unknown; else:
3954 %define CAUSEMASK ((1 << 23) | (1 << 22) | (3 << 8))
3955 mov eax, CP0_Cause ; eax := CP0_Cause
3956 and ebx, CAUSEMASK ; T := T & CAUSEMASK
3957 and eax, ~CAUSEMASK ; eax := eax & ~CAUSEMASK
3958 or eax, ebx ; eax := eax | T
3959 mov CP0_Cause, eax ; CP0_Cause := eax
3960 jmp _end_cycle ; Done
3961 ;-----------------------------------------------------------------------------
3962 _mtc0_r14: ; 0x0e
3963 test ecx, ecx ; Sel != 0 ?
3964 jnz _mtc0_unknown ; ... then unknown; else:
3965 mov Sr(CP0_Epc), ebx ; CP0_Epc := T
3966 jmp _end_cycle ; Done
3967 ;-----------------------------------------------------------------------------
3968 _mtc0_r15: ; 0x0f
3969 jmp _mtc0_unknown
3970 ;-----------------------------------------------------------------------------
3971 _mtc0_r16: ; 0x10
3972 jmp _end_cycle ; Done
3973 ;-----------------------------------------------------------------------------
3974 _mtc0_r17: ; 0x11
3975 jmp _mtc0_unknown
3976 ;-----------------------------------------------------------------------------
3977 _mtc0_r18: ; 0x12
3978 jmp _end_cycle ; Done
3979 ;-----------------------------------------------------------------------------
3980 _mtc0_r19: ; 0x13
3981 jmp _end_cycle ; Done
3982 ;-----------------------------------------------------------------------------
3983 _mtc0_r20: ; 0x14
3984 jmp _mtc0_unknown ; Done
3985 ;-----------------------------------------------------------------------------
3986 _mtc0_r21: ; 0x15
3987 jmp _mtc0_unknown ; Done
3988 ;-----------------------------------------------------------------------------
3989 _mtc0_r22: ; 0x16
3990 jmp _mtc0_unknown ; Done
3991 ;-----------------------------------------------------------------------------
3992 _mtc0_r23: ; 0x17
3993 jmp _mtc0_unknown ; Done
3994 ;-----------------------------------------------------------------------------
3995 _mtc0_r24: ; 0x18
3996 jmp _mtc0_unknown ; Done
3997 ;-----------------------------------------------------------------------------
3998 _mtc0_r25: ; 0x19
3999 jmp _mtc0_unknown ; Done
4000 ;-----------------------------------------------------------------------------
4001 _mtc0_r26: ; 0x1a
4002 jmp _mtc0_unknown ; Done
4003 ;-----------------------------------------------------------------------------
4004 _mtc0_r27: ; 0x1b
4005 jmp _mtc0_unknown ; Done
4006 ;-----------------------------------------------------------------------------
4007 _mtc0_r28: ; 0x1c
4008 jmp _mtc0_unknown ; Done
4009 ;-----------------------------------------------------------------------------
4010 _mtc0_r29: ; 0x1d
4011 jmp _mtc0_unknown ; Done
4012 ;-----------------------------------------------------------------------------
4013 _mtc0_r30: ; 0x1e
4014 jmp _mtc0_unknown ; Done
4015 ;-----------------------------------------------------------------------------
4016 _mtc0_r31: ; 0x1f
4017 jmp _mtc0_unknown ; Done
4018 ;-----------------------------------------------------------------------------
4019 _mtc0_unknown:
4020 ; 'The results are UNDEFINED if coprocessor 0 does not contain a
4021 ; register as specified by rd and sel.'
4022 ACHTUNG "Unknown CP0 Reg Selector in MTC0!" ;; TODO: print detail
4023 jmp _end_cycle ; Done
4024 ;-----------------------------------------------------------------------------
4025
4026 ;-----------------------------------------------------------------------------
4027 ; WAIT - Enter Standby Mode.
4028 ; Wait for Event.
4029 ; Puts the emulator into 'wait' mode.
4030 ; Encoding: 0100 001- ---- ---- ---- ---- --10 0000
4031 ; PRIVILEGED (permitted in Kernel Mode only.)
4032 ;-----------------------------------------------------------------------------
4033 align GRAIN, db 0x90
4034 _m_wait:
4035 ; no fields
4036 Flg_On Waiting ; Set 'Waiting' Flag.
4037 jmp _end_cycle
4038 ;-----------------------------------------------------------------------------
-
+ 40EF74622647A11AC973984A9F831AD39BBEC47EAC267E3F62FB30E36058AC4B01074B97585E9B36E0B32DEB7344EC4C5AA6585E9571BAA2E0432E8D78DEB254
m/mipsinst/r_instrs.asm
(0 . 0)(1 . 662)
4043 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4044 ;; ;;
4045 ;; This file is part of 'M', a MIPS system emulator. ;;
4046 ;; ;;
4047 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
4048 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
4049 ;; ;;
4050 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
4051 ;; distribute this software ; Should you use this software for any purpose, ;;
4052 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
4053 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
4054 ;; continue doing so for the indefinite future. In any case, please ;;
4055 ;; always : read and understand any software ; verify any PGP signatures ;;
4056 ;; that you use - for any purpose. ;;
4057 ;; ;;
4058 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
4059 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4060
4061 ;; TODO: 1) Traps in ADD and SUB (gcc 4.8.1 doesn't seem to use. but do exist)
4062 ;; 2) Tests!!!
4063
4064 ;----------------------------
4065 ; R-Type MIPS Instructions: |
4066 ;----------------------------
4067
4068 ;-----------------------------------------------------------------------------
4069 section .rodata
4070 align GRAIN, db 0x90
4071 _R_Table:
4072 A32 _r_sll ; 0x00 : sll (000000????????????????????000000)
4073 A32 _bad ; 0x01 : UNDEFINED
4074 A32 _r_srl ; 0x02 : srl (000000????????????????????000010)
4075 A32 _r_sra ; 0x03 : sra (000000????????????????????000011)
4076 A32 _r_sllv ; 0x04 : sllv (000000????????????????????000100)
4077 A32 _bad ; 0x05 : UNDEFINED
4078 A32 _r_srlv ; 0x06 : srlv (000000????????????????????000110)
4079 A32 _r_srav ; 0x07 : srav (000000????????????????????000111)
4080 A32 _r_jr ; 0x08 : jr (000000????????????????????001000)
4081 A32 _r_jalr ; 0x09 : jalr (000000????????????????????001001)
4082 A32 _r_movz ; 0x0a : movz (000000???????????????00000001010)
4083 A32 _r_movn ; 0x0b : movn (000000???????????????00000001011)
4084 A32 _r_syscall ; 0x0c : syscall (000000????????????????????001100)
4085 A32 _bad ; 0x0d : UNDEFINED
4086 A32 _bad ; 0x0e : UNDEFINED
4087 A32 _r_sync ; 0x0f : sync (000000????????????????????001111)
4088 A32 _r_mfhi ; 0x10 : mfhi (000000????????????????????010000)
4089 A32 _r_mthi ; 0x11 : mthi (000000????????????????????010001)
4090 A32 _r_mflo ; 0x12 : mflo (000000????????????????????010010)
4091 A32 _r_mtlo ; 0x13 : mtlo (000000????????????????????010011)
4092 A32 _bad ; 0x14 : UNDEFINED
4093 A32 _bad ; 0x15 : UNDEFINED
4094 A32 _bad ; 0x16 : UNDEFINED
4095 A32 _bad ; 0x17 : UNDEFINED
4096 A32 _r_mult ; 0x18 : mult (000000????????????????????011000)
4097 A32 _r_multu ; 0x19 : multu (000000????????????????????011001)
4098 A32 _r_div ; 0x1a : div (000000????????????????????011010)
4099 A32 _r_divu ; 0x1b : divu (000000????????????????????011011)
4100 A32 _bad ; 0x1c : UNDEFINED
4101 A32 _bad ; 0x1d : UNDEFINED
4102 A32 _bad ; 0x1e : UNDEFINED
4103 A32 _bad ; 0x1f : UNDEFINED
4104 A32 _r_add ; 0x20 : add (000000????????????????????100000)
4105 A32 _r_addu ; 0x21 : addu (000000????????????????????100001)
4106 A32 _r_sub ; 0x22 : sub (000000????????????????????100010)
4107 A32 _r_subu ; 0x23 : subu (000000????????????????????100011)
4108 A32 _r_and ; 0x24 : and (000000????????????????????100100)
4109 A32 _r_or ; 0x25 : or (000000????????????????????100101)
4110 A32 _r_xor ; 0x26 : xor (000000????????????????????100110)
4111 A32 _r_nor ; 0x27 : nor (000000????????????????????100111)
4112 A32 _bad ; 0x28 : UNDEFINED
4113 A32 _bad ; 0x29 : UNDEFINED
4114 A32 _r_slt ; 0x2a : slt (000000????????????????????101010)
4115 A32 _r_sltu ; 0x2b : sltu (000000????????????????????101011)
4116 A32 _bad ; 0x2c : UNDEFINED
4117 A32 _bad ; 0x2d : UNDEFINED
4118 A32 _bad ; 0x2e : UNDEFINED
4119 A32 _bad ; 0x2f : UNDEFINED
4120 A32 _bad ; 0x30 : UNDEFINED
4121 A32 _bad ; 0x31 : UNDEFINED
4122 A32 _bad ; 0x32 : UNDEFINED
4123 A32 _bad ; 0x33 : UNDEFINED
4124 A32 _r_teq ; 0x34 : teq (000000????????????????????110100)
4125 A32 _bad ; 0x35 : UNDEFINED
4126 A32 _r_tne ; 0x36 : tne (000000????????????????????110110)
4127 A32 _bad ; 0x37 : UNDEFINED
4128 A32 _bad ; 0x38 : UNDEFINED
4129 A32 _bad ; 0x39 : UNDEFINED
4130 A32 _bad ; 0x3a : UNDEFINED
4131 A32 _bad ; 0x3b : UNDEFINED
4132 A32 _bad ; 0x3c : UNDEFINED
4133 A32 _bad ; 0x3d : UNDEFINED
4134 A32 _bad ; 0x3e : UNDEFINED
4135 A32 _bad ; 0x3f : UNDEFINED
4136 ;-----------------------------------------------------------------------------
4137
4138 section .text
4139
4140 ;-----------------------------------------------------------------------------
4141 ; SLL -- Shift left logical.
4142 ; Shifts a register value left by the shift amount listed in the instruction
4143 ; and places the result in a third register. Zeroes are shifted in.
4144 ; Operation: $d = $t << h; advance_pc(4);
4145 ; Syntax: sll $d, $t, h
4146 ; Encoding: 0000 00-- ---t tttt dddd dhhh hh00 0000
4147 ;-----------------------------------------------------------------------------
4148 align GRAIN, db 0x90
4149 _r_sll:
4150 RType_D_T_Shamt ; load rS, rT, Shamt Fields
4151 mov TMP, R(rT) ; TMP := Regs[rT]
4152 shl TMP, cl ; TMP := TMP << CL (Shamt is in ECX)
4153 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4154 jmp _end_cycle
4155 ;-----------------------------------------------------------------------------
4156
4157 ;-----------------------------------------------------------------------------
4158 ; SRL -- Shift right logical.
4159 ; Shifts a register value right by the shift amount (shamt) and places the
4160 ; value in the destination register. Zeroes are shifted in.
4161 ; Operation: $d = $t >> h; advance_pc(4);
4162 ; Syntax: srl $d, $t, h
4163 ; Encoding: 0000 00-- ---t tttt dddd dhhh hh00 0010
4164 ;-----------------------------------------------------------------------------
4165 align GRAIN, db 0x90
4166 _r_srl:
4167 RType_D_T_Shamt ; load rS, rT, Shamt Fields
4168 mov TMP, R(rT) ; TMP := Regs[rT]
4169 shr TMP, cl ; TMP := TMP >> CL (Shamt is in ECX)
4170 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4171 jmp _end_cycle
4172 ;-----------------------------------------------------------------------------
4173
4174 ;-----------------------------------------------------------------------------
4175 ; SRA -- Shift right arithmetic.
4176 ; Shifts a register value right by the shift amount (shamt) and places the
4177 ; value in the destination register. The sign bit is shifted in.
4178 ; Operation: $d = $t >> h; advance_pc(4);
4179 ; Syntax: sra $d, $t, h
4180 ; Encoding: 0000 00-- ---t tttt dddd dhhh hh00 0011
4181 ;-----------------------------------------------------------------------------
4182 align GRAIN, db 0x90
4183 _r_sra:
4184 RType_D_T_Shamt ; load rS, rT, Shamt Fields
4185 mov TMP, R(rT) ; TMP := Regs[rT]
4186 sar TMP, cl ; TMP := TMP >>(sgn) CL (Shamt is in ECX)
4187 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4188 jmp _end_cycle
4189 ;-----------------------------------------------------------------------------
4190
4191 ;-----------------------------------------------------------------------------
4192 ; SLLV -- Shift left logical variable.
4193 ; Shifts a register value left by the value in a second register and places
4194 ; the result in a third register. Zeroes are shifted in.
4195 ; Operation: $d = $t << $s; advance_pc(4);
4196 ; Syntax: sllv $d, $t, $s
4197 ; Encoding: 0000 00ss ssst tttt dddd d--- --00 0100
4198 ;-----------------------------------------------------------------------------
4199 align GRAIN, db 0x90
4200 _r_sllv:
4201 RType ; load rD, rS, rT Fields
4202 mov ecx, R(rS) ; Now CL is the shift amount
4203 mov TMP, R(rT) ; TMP := Regs[rT]
4204 shl TMP, cl ; TMP := TMP << CL
4205 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4206 jmp _end_cycle
4207 ;-----------------------------------------------------------------------------
4208
4209 ;-----------------------------------------------------------------------------
4210 ; SRLV -- Shift right logical variable.
4211 ; Shifts a register value right by the amount specified in $s and places the
4212 ; value in the destination register. Zeroes are shifted in.
4213 ; Operation: $d = $t >> $s; advance_pc(4);
4214 ; Syntax: srlv $d, $t, $s
4215 ; Encoding: 0000 00ss ssst tttt dddd d000 0000 0110
4216 ;-----------------------------------------------------------------------------
4217 align GRAIN, db 0x90
4218 _r_srlv:
4219 RType ; load rD, rS, rT Fields
4220 mov ecx, R(rS) ; Now CL is the shift amount
4221 mov TMP, R(rT) ; TMP := Regs[rT]
4222 shr TMP, cl ; TMP := TMP >> CL
4223 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4224 jmp _end_cycle
4225 ;-----------------------------------------------------------------------------
4226
4227 ;-----------------------------------------------------------------------------
4228 ; SRAV - Shift Word Right Arithmetic Variable.
4229 ; Execute an arithmetic right-shift of a word by a variable number of bits.
4230 ; The contents of the low-order 32-bit word of rT are shifted right,
4231 ; duplicating the sign-bit (bit 31) in the emptied bits; the word result is
4232 ; placed in rD. The bit-shift amount is specified by the low-order 5 bits
4233 ; of rS.
4234 ; Operation: $d = $t >> $s; advance_pc(4);
4235 ; Syntax: srav $d, $t, $s
4236 ; Encoding: 0000 00ss ssst tttt dddd d000 0000 0111
4237 ;-----------------------------------------------------------------------------
4238 align GRAIN, db 0x90
4239 _r_srav:
4240 RType ; load rD, rS, rT Fields
4241 mov ecx, R(rS) ; Now CL is the shift amount
4242 mov TMP, R(rT) ; TMP := Regs[rT]
4243 sar TMP, cl ; TMP := TMP >> CL (extends sign bit)
4244 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4245 jmp _end_cycle
4246 ;-----------------------------------------------------------------------------
4247
4248 ;-----------------------------------------------------------------------------
4249 ; JR -- Jump register.
4250 ; Jump to the address contained in register $s
4251 ; Operation: PC = nPC; nPC = $s;
4252 ; Syntax: jr $s
4253 ; Encoding: 0000 00ss sss0 0000 0000 0000 0000 1000
4254 ;-----------------------------------------------------------------------------
4255 align GRAIN, db 0x90
4256 _r_jr:
4257 RType_S_Only ; Load rS Field
4258 mov nPC, R(rS) ; nPC := Regs[rS]
4259 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
4260 jmp _end_cycle
4261 ;-----------------------------------------------------------------------------
4262
4263 ;-----------------------------------------------------------------------------
4264 ; JALR - Jump and Link Register.
4265 ; Execute a procedure call to an instruction address in a register.
4266 ; Place the return address link in rD. The return link is the address of the
4267 ; second instruction following the branch, where execution continues after a
4268 ; procedure call. Jump to the effective target address in rS. Execute the
4269 ; instruction that follows the jump, in the branch delay slot, before
4270 ; executing the jump itself.
4271 ; Operation: $d = PC + 8; PC = nPC; nPC = $s
4272 ; Syntax: jalr $s
4273 ; Encoding: 0000 00ss sss0 0000 dddd 0000 0000 1001
4274 ;-----------------------------------------------------------------------------
4275 align GRAIN, db 0x90
4276 _r_jalr:
4277 RType_S_D_Only ; Load rD and rS Fields
4278 mov nPC, R(rS) ; nPC := Regs[rS]
4279 mov TMP, PC ; TMP := PC
4280 add TMP, 0x8 ; TMP := TMP + 8
4281 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4282 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
4283 jmp _end_cycle
4284 ;-----------------------------------------------------------------------------
4285
4286 ;-----------------------------------------------------------------------------
4287 ; MOVZ - Move Conditional on Zero.
4288 ; Conditionally move a register after testing a register value.
4289 ; If the value in rT is equal to zero, then the contents of rS are placed
4290 ; into rD.
4291 ; Operation: if $t = 0 then $d = $s
4292 ; Syntax: movz $d, $s, $t
4293 ; Encoding: 0000 00ss ssst tttt dddd d000 0000 1010
4294 ;-----------------------------------------------------------------------------
4295 ; TODO: measure if the cmov is actually faster than a branch here !
4296 ; TODO: untested
4297 align GRAIN, db 0x90
4298 _r_movz:
4299 ; UNDONE_INST
4300 RType ; load rD, rS, rT Fields
4301 mov TMP, R(rT) ; TMP := Regs[rT]
4302 test TMP, TMP ; Set Z flag if TMP = 0
4303 mov TMP, R(rD) ; First, move Regs[rD] to TMP
4304 cmovz TMP, R(rS) ; If Z flag set, overwrite with Regs[rS]
4305 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4306 jmp _end_cycle
4307 ;-----------------------------------------------------------------------------
4308
4309 ;-----------------------------------------------------------------------------
4310 ; MOVN - Move Conditional on Not Zero.
4311 ; Conditionally move a register after testing a register value.
4312 ; If the value in rT is NOT equal to zero, then the contents of rS are placed
4313 ; into rD.
4314 ; Operation: if $t != 0 then $d = $s
4315 ; Syntax: movn $d, $s, $t
4316 ; Encoding: 0000 00ss ssst tttt dddd d000 0000 1011
4317 ;-----------------------------------------------------------------------------
4318 ; TODO: measure if the cmov is actually faster than a branch here !
4319 ; TODO: untested
4320 align GRAIN, db 0x90
4321 _r_movn:
4322 ; UNDONE_INST
4323 RType ; load rD, rS, rT Fields
4324 mov TMP, R(rT) ; TMP := Regs[rT]
4325 test TMP, TMP ; Set Z flag if TMP = 0
4326 mov TMP, R(rD) ; First, move Regs[rD] to TMP
4327 cmovnz TMP, R(rS) ; If Z not set, overwrite with Regs[rS]
4328 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4329 jmp _end_cycle
4330 ;-----------------------------------------------------------------------------
4331
4332 ;-----------------------------------------------------------------------------
4333 ; SYSCALL -- System call.
4334 ; Generates a software interrupt.
4335 ; Operation: advance_pc(4);
4336 ; Syntax: syscall
4337 ; Encoding: 0000 00-- ---- ---- ---- ---- --00 1100
4338 ;-----------------------------------------------------------------------------
4339 align GRAIN, db 0x90
4340 _r_syscall:
4341 ; no fields
4342 SetEXC EXC_SYS ; Set the EXC_SYS Exception
4343 jmp _Handle_Exception ; Go straight to exception handler.
4344 ;-----------------------------------------------------------------------------
4345
4346 ;-----------------------------------------------------------------------------
4347 ; SYNC - Synchronize Shared Memory.
4348 ; Operation: This is a NOP in this emulator.
4349 ; Syntax: sync
4350 ; Encoding: 0000 0000 0000 0000 0000 0000 0000 1111
4351 ;-----------------------------------------------------------------------------
4352 align GRAIN, db 0x90
4353 _r_sync:
4354 jmp _end_cycle
4355 ;-----------------------------------------------------------------------------
4356
4357 ;-----------------------------------------------------------------------------
4358 ; MFHI -- Move from HI.
4359 ; The contents of special register HI are moved to the specified register.
4360 ; Operation: $d = $HI; advance_pc(4);
4361 ; Syntax: mfhi $d
4362 ; Encoding: 0000 0000 0000 0000 dddd d000 0001 0000
4363 ;-----------------------------------------------------------------------------
4364 align GRAIN, db 0x90
4365 _r_mfhi:
4366 RType_D_Only ; Load rD Field
4367 mov TMP, Sr(HI) ; TMP := Sr(HI)
4368 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4369 jmp _end_cycle
4370 ;-----------------------------------------------------------------------------
4371
4372 ;-----------------------------------------------------------------------------
4373 ; MTHI - Move to HI Register.
4374 ; The contents of rS are loaded to the special register HI.
4375 ; Operation: $HI = $s
4376 ; Syntax: mthi $s
4377 ; Encoding: 0000 00ss sss0 0000 0000 0000 0001 0001
4378 ;-----------------------------------------------------------------------------
4379 align GRAIN, db 0x90
4380 _r_mthi:
4381 RType_S_Only ; Load rS Field
4382 mov TMP, R(rS) ; TMP := Regs[rS]
4383 mov Sr(HI), TMP ; HI := TMP
4384 jmp _end_cycle
4385 ;-----------------------------------------------------------------------------
4386
4387 ;-----------------------------------------------------------------------------
4388 ; MFLO -- Move from LO.
4389 ; The contents of register LO are moved to the specified register.
4390 ; Operation: $d = $LO; advance_pc(4);
4391 ; Syntax: mflo $d
4392 ; Encoding: 0000 0000 0000 0000 dddd d000 0001 0010
4393 ;-----------------------------------------------------------------------------
4394 align GRAIN, db 0x90
4395 _r_mflo:
4396 RType_D_Only ; Load rD Field
4397 mov TMP, Sr(LO) ; TMP := Sr(LO)
4398 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4399 jmp _end_cycle
4400 ;-----------------------------------------------------------------------------
4401
4402 ;-----------------------------------------------------------------------------
4403 ; MTLO - Move to LO.
4404 ; The contents of rS are loaded to the special register LO.
4405 ; Operation: $LO = $s
4406 ; Syntax: mtlo $s
4407 ; Encoding: 0000 00ss sss0 0000 0000 0000 0001 0011
4408 ;-----------------------------------------------------------------------------
4409 align GRAIN, db 0x90
4410 _r_mtlo:
4411 RType_S_Only ; Load rS Field
4412 mov TMP, R(rS) ; TMP := Regs[rS]
4413 mov Sr(LO), TMP ; LO := TMP
4414 jmp _end_cycle
4415 ;-----------------------------------------------------------------------------
4416
4417 ;-----------------------------------------------------------------------------
4418 ; MULT -- Multiply signed.
4419 ; Multiplies $s by $t and stores the result in $HI:$LO.
4420 ; Operation: $HI:$LO = $s * $t; advance_pc(4);
4421 ; Syntax: mult $s, $t
4422 ; Encoding: 0000 00ss ssst tttt 0000 0000 0001 1000
4423 ;-----------------------------------------------------------------------------
4424 align GRAIN, db 0x90
4425 _r_mult:
4426 RType_S_T_Only
4427 mov eax, R(rT) ; eax := Regs[rT]
4428 imul R(rS) ; edx:eax := Regs[rS] * eax (signed)
4429 mov Sr(LO), eax ; LO := Bottom 32 bits of product
4430 mov Sr(HI), edx ; HI := Top 32 bits of product
4431 jmp _end_cycle
4432 ;-----------------------------------------------------------------------------
4433
4434 ;-----------------------------------------------------------------------------
4435 ; MULTU -- Multiply unsigned.
4436 ; Multiplies $s by $t and stores the result in $HI:$LO.
4437 ; Operation: $HI:$LO = $s * $t; advance_pc(4);
4438 ; Syntax: multu $s, $t
4439 ; Encoding: 0000 00ss ssst tttt 0000 0000 0001 1001
4440 ;-----------------------------------------------------------------------------
4441 align GRAIN, db 0x90
4442 _r_multu:
4443 RType_S_T_Only ; Load rS and rT Fields
4444 mov eax, R(rT) ; eax := Regs[rT]
4445 mul R(rS) ; edx:eax := Regs[rS] * eax (unsigned)
4446 mov Sr(LO), eax ; LO := Bottom 32 bits of product
4447 mov Sr(HI), edx ; HI := Top 32 bits of product
4448 jmp _end_cycle
4449 ;-----------------------------------------------------------------------------
4450
4451 ;-----------------------------------------------------------------------------
4452 ; DIV -- Divide signed.
4453 ; Divides $s by $t and stores the quotient in $LO and the remainder in $HI
4454 ; Operation: $LO = $s / $t; $HI = $s % $t; advance_pc(4);
4455 ; Syntax: div $s, $t
4456 ; Encoding: 0000 00ss ssst tttt 0000 0000 0001 1010
4457 ;-----------------------------------------------------------------------------
4458 ; TODO: detect div0 and other special cases
4459 align GRAIN, db 0x90
4460 _r_div:
4461 RType_S_T_Only ; Load rS and rT Fields
4462 mov eax, R(rS) ; eax := Regs[rS]
4463 cdq ; extend sign of eax into edx
4464 cmp R(rT), 0 ; test for div0
4465 je _r_div_div0 ; div0 is undefined result
4466 idiv R(rT) ; edx:eax / Regs[rT]; edx := r, eax := q
4467 mov Sr(LO), eax ; LO := edx:eax /(signed) ecx (quotient)
4468 mov Sr(HI), edx ; HI := edx:eax %(signed) ecx (remainder)
4469 _r_div_div0:
4470 jmp _end_cycle
4471 ;-----------------------------------------------------------------------------
4472
4473 ;-----------------------------------------------------------------------------
4474 ; DIVU -- Divide unsigned.
4475 ; Divides $s by $t and stores the quotient in $LO and the remainder in $HI
4476 ; Operation: $LO = $s / $t; $HI = $s % $t; advance_pc(4);
4477 ; Syntax: divu $s, $t
4478 ; Encoding: 0000 00ss ssst tttt 0000 0000 0001 1011
4479 ;-----------------------------------------------------------------------------
4480 ; TODO: detect div0 and other special cases
4481 align GRAIN, db 0x90
4482 _r_divu:
4483 RType_S_T_Only ; Load rS and rT Fields
4484 xor edx, edx ; edx := 0
4485 mov eax, R(rS) ; eax := Regs[rS]
4486 cmp R(rT), 0 ; test for div0
4487 je _r_divu_div0 ; div0 is undefined result
4488 div R(rT) ; edx:eax / Regs[rT]; edx := r, eax := q
4489 mov Sr(LO), eax ; LO := edx:eax / ecx (quotient)
4490 mov Sr(HI), edx ; HI := edx:eax % ecx (remainder)
4491 _r_divu_div0:
4492 jmp _end_cycle
4493 ;-----------------------------------------------------------------------------
4494
4495 ;-----------------------------------------------------------------------------
4496 ; ADD -- Add (with overflow).
4497 ; Adds two registers and stores the result in a register
4498 ; Operation: $d = $s + $t; advance_pc(4);
4499 ; Syntax: add $d, $s, $t
4500 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0000
4501 ;-----------------------------------------------------------------------------
4502 align GRAIN, db 0x90
4503 _r_add:
4504 RType ; load rD, rS, rT Fields
4505 mov TMP, R(rS) ; TMP := Regs[rS]
4506 add TMP, R(rT) ; TMP := Regs[rS] + Regs[rT]
4507 ; TODO: detect/trap overflow
4508 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4509 jmp _end_cycle
4510 ;-----------------------------------------------------------------------------
4511
4512 ;-----------------------------------------------------------------------------
4513 ; ADDU -- Add unsigned (no overflow).
4514 ; Adds two registers and stores the result in a register
4515 ; Operation: $d = $s + $t; advance_pc(4);
4516 ; Syntax: addu $d, $s, $t
4517 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0001
4518 ;-----------------------------------------------------------------------------
4519 align GRAIN, db 0x90
4520 _r_addu:
4521 RType ; load rD, rS, rT Fields
4522 mov TMP, R(rS) ; TMP := Regs[rS]
4523 add TMP, R(rT) ; TMP := Regs[rS] + Regs[rT]
4524 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4525 jmp _end_cycle
4526 ;-----------------------------------------------------------------------------
4527
4528 ;-----------------------------------------------------------------------------
4529 ; SUB -- Subtract.
4530 ; Subtracts two registers and stores the result in a register
4531 ; Operation: $d = $s - $t; advance_pc(4);
4532 ; Syntax: sub $d, $s, $t
4533 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0010
4534 ;-----------------------------------------------------------------------------
4535 align GRAIN, db 0x90
4536 _r_sub:
4537 RType ; load rD, rS, rT Fields
4538 mov TMP, R(rS) ; TMP := Regs[rS]
4539 sub TMP, R(rT) ; TMP := Regs[rS] - Regs[rT]
4540 ; TODO: detect and trap overflow
4541 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4542 jmp _end_cycle
4543 ;-----------------------------------------------------------------------------
4544
4545 ;-----------------------------------------------------------------------------
4546 ; SUBU -- Subtract unsigned.
4547 ; Subtracts two registers and stores the result in a register
4548 ; Operation: $d = $s - $t; advance_pc(4);
4549 ; Syntax: subu $d, $s, $t
4550 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0011
4551 ;-----------------------------------------------------------------------------
4552 align GRAIN, db 0x90
4553 _r_subu:
4554 RType ; load rD, rS, rT Fields
4555 mov TMP, R(rS) ; TMP := Regs[rS]
4556 sub TMP, R(rT) ; TMP := Regs[rS] - Regs[rT]
4557 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4558 jmp _end_cycle
4559 ;-----------------------------------------------------------------------------
4560
4561 ;-----------------------------------------------------------------------------
4562 ; AND -- Bitwise AND.
4563 ; Bitwise ANDs two registers and stores the result in a register
4564 ; Operation: $d = $s & $t; advance_pc(4);
4565 ; Syntax: and $d, $s, $t
4566 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0100
4567 ;-----------------------------------------------------------------------------
4568 align GRAIN, db 0x90
4569 _r_and:
4570 RType ; load rD, rS, rT Fields
4571 mov TMP, R(rS) ; TMP := Regs[rS]
4572 and TMP, R(rT) ; TMP := TMP & Regs[rT]
4573 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4574 jmp _end_cycle
4575 ;-----------------------------------------------------------------------------
4576
4577 ;-----------------------------------------------------------------------------
4578 ; OR -- Bitwise OR.
4579 ; Bitwise logical ORs two registers and stores the result in a register
4580 ; Operation: $d = $s | $t; advance_pc(4);
4581 ; Syntax: or $d, $s, $t
4582 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0101
4583 ;-----------------------------------------------------------------------------
4584 align GRAIN, db 0x90
4585 _r_or:
4586 RType ; load rD, rS, rT Fields
4587 mov TMP, R(rS) ; TMP := Regs[rS]
4588 or TMP, R(rT) ; TMP := TMP | Regs[rT]
4589 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4590 jmp _end_cycle
4591 ;-----------------------------------------------------------------------------
4592
4593 ;-----------------------------------------------------------------------------
4594 ; XOR -- Bitwise Exclusive OR.
4595 ; Exclusive ORs two registers and stores the result in a register
4596 ; Operation: $d = $s ^ $t; advance_pc(4);
4597 ; Syntax: xor $d, $s, $t
4598 ; Encoding: 0000 00ss ssst tttt dddd d--- --10 0110
4599 ;-----------------------------------------------------------------------------
4600 align GRAIN, db 0x90
4601 _r_xor:
4602 RType ; load rD, rS, rT Fields
4603 mov TMP, R(rS) ; TMP := Regs[rS]
4604 xor TMP, R(rT) ; TMP := TMP ^ Regs[rT]
4605 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4606 jmp _end_cycle
4607 ;-----------------------------------------------------------------------------
4608
4609 ;-----------------------------------------------------------------------------
4610 ; NOR - Not OR.
4611 ; Do a bitwise logical NOT OR.
4612 ; The contents of rS are combined with the contents of rT in a bitwise logical
4613 ; NOR operation. The result is placed into rD.
4614 ; Operation: $d = $s NOR $t
4615 ; Syntax: nor $d, $s, $t
4616 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 0111
4617 ;-----------------------------------------------------------------------------
4618 align GRAIN, db 0x90
4619 _r_nor:
4620 RType ; load rD, rS, rT Fields
4621 mov TMP, R(rS) ; TMP := Regs[rS]
4622 or TMP, R(rT) ; TMP := TMP | Regs[rT]
4623 not TMP ; TMP := ~TMP
4624 Wr_Reg rD, TMP ; Regs[rD] := TMP (result)
4625 jmp _end_cycle
4626 ;-----------------------------------------------------------------------------
4627
4628 ;-----------------------------------------------------------------------------
4629 ; SLT -- Set on less than (signed).
4630 ; If $s is less than $t, $d is set to one. It gets zero otherwise.
4631 ; Operation: if $s < $t $d = 1; advance_pc(4); else $d = 0; advance_pc(4);
4632 ; Syntax: slt $d, $s, $t
4633 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 1010
4634 ;-----------------------------------------------------------------------------
4635 align GRAIN, db 0x90
4636 _r_slt:
4637 RType ; load rD, rS, rT Fields
4638 mov TMP, R(rS) ; TMP := Regs[rS]
4639 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
4640 ; We do not need rS, so can reuse it here:
4641 setl rS_LowByte ; 1 if R(rS) <(signed) R(rT), else 0
4642 and rS, 0x1 ; Only want the bit that we have set
4643 Wr_Reg rD, rS ; Regs[rD] := result
4644 jmp _end_cycle
4645 ;-----------------------------------------------------------------------------
4646
4647 ;-----------------------------------------------------------------------------
4648 ; SLTU -- Set on less than unsigned.
4649 ; If $s is less than $t, $d is set to one. It gets zero otherwise.
4650 ; Operation: if $s < $t $d = 1; advance_pc(4); else $d = 0; advance_pc(4);
4651 ; Syntax: sltu $d, $s, $t
4652 ; Encoding: 0000 00ss ssst tttt dddd d000 0010 1011
4653 ;-----------------------------------------------------------------------------
4654 align GRAIN, db 0x90
4655 _r_sltu:
4656 RType ; load rD, rS, rT Fields
4657 mov TMP, R(rS) ; TMP := Regs[rS]
4658 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
4659 ; We do not need rS, so can reuse it here:
4660 setb rS_LowByte ; 1 if R(rS) <(signed) R(rT), else 0
4661 and rS, 0x1 ; Only want the bit that we have set
4662 Wr_Reg rD, rS ; Regs[rD] := result
4663 jmp _end_cycle
4664 ;-----------------------------------------------------------------------------
4665
4666 ;-----------------------------------------------------------------------------
4667 ; TEQ - Trap if Equal.
4668 ; TODO: document
4669 ;-----------------------------------------------------------------------------
4670 align GRAIN, db 0x90
4671 _r_teq:
4672 RType_S_T_Only ; Load rS and rT Fields
4673 mov TMP, R(rS) ; TMP := Regs[rS]
4674 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
4675 jne _r_teq_neql
4676 SetEXC EXC_Tr ; Spring the Trap Exception.
4677 jmp _Handle_Exception ; Go straight to exception handler.
4678 _r_teq_neql:
4679 jmp _end_cycle
4680 ;-----------------------------------------------------------------------------
4681
4682 ;-----------------------------------------------------------------------------
4683 ; TNE - Trap if Not Equal.
4684 ; Compare registers and do a conditional trap.
4685 ; Compare the contents of rS and rT as signed integers;
4686 ; if rS is not equal to rT, then take a Trap exception.
4687 ; The contents of the code field are ignored by hardware and may be used to
4688 ; encode information for system software. To retrieve the information,
4689 ; system software must load the instruction word from memory.
4690 ; Operation: if $s != $t then Trap
4691 ; Syntax: TNE $s, $t
4692 ; Encoding: 0000 00ss ssst tttt cccc cccc cc11 0110
4693 ;-----------------------------------------------------------------------------
4694 align GRAIN, db 0x90
4695 _r_tne:
4696 RType_S_T_Only ; Load rS and rT Fields
4697 mov TMP, R(rS) ; TMP := Regs[rS]
4698 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
4699 je _r_tne_eql
4700 SetEXC EXC_Tr ; Spring the Trap Exception.
4701 jmp _Handle_Exception ; Go straight to exception handler.
4702 _r_tne_eql:
4703 jmp _end_cycle
4704 ;-----------------------------------------------------------------------------
-
+ 519EF7801EACB6D41C79E217D6E4CE28EA37F45C50EB4F77D968459C8143957A5EC15C68448FFAE06CC5DA31A15F53C258DB402ACF1AE08C3C940E502B734D73
m/misc/m.gdb
(0 . 0)(1 . 11)
4709 set architecture i386:x86-64
4710 set disassemble-next-line on
4711 set disassembly-flavor intel
4712 set confirm off
4713 set height 0
4714
4715 file bin/m
4716
4717 b _start
4718
4719 r lin_be.bin
-
+ 63181E522486B260324663A2C7CB928E8110114503A0711AC596F35176CB774BCA680F59C83B3723A3ABC4EB57A3FA3D10A657CA6E6BC79A4A3706325279068B
m/os/linux.asm
(0 . 0)(1 . 236)
4724 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4725 ;; ;;
4726 ;; This file is part of 'M', a MIPS system emulator. ;;
4727 ;; ;;
4728 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
4729 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
4730 ;; ;;
4731 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
4732 ;; distribute this software ; Should you use this software for any purpose, ;;
4733 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
4734 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
4735 ;; continue doing so for the indefinite future. In any case, please ;;
4736 ;; always : read and understand any software ; verify any PGP signatures ;;
4737 ;; that you use - for any purpose. ;;
4738 ;; ;;
4739 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
4740 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4741
4742 ;-----------------------------------------------------------------------------
4743 %macro PUSHA 0
4744 push rax
4745 push rbx
4746 push rcx
4747 push rdx
4748 push rbp
4749 push rdi
4750 push rsi
4751 push r8
4752 push r9
4753 push r10
4754 push r11
4755 push r12
4756 push r13
4757 push r14
4758 push r15
4759
4760 ; lea rsp,[rsp-16*4]
4761 ; movdqu [rsp+16*0], xmm0
4762 ; movdqu [rsp+16*1], xmm1
4763 ; movdqu [rsp+16*2], xmm2
4764 ; movdqu [rsp+16*3], xmm2
4765
4766 %endmacro
4767 ;-----------------------------------------------------------------------------
4768
4769 ;-----------------------------------------------------------------------------
4770 %macro POPA 0
4771
4772 ; movdqu xmm1,[rsp+16*3]
4773 ; movdqu xmm1,[rsp+16*2]
4774 ; movdqu xmm1,[rsp+16*1]
4775 ; movdqu xmm0,[rsp+16*0]
4776 ; lea rsp,[rsp+16*4]
4777
4778 pop r15
4779 pop r14
4780 pop r13
4781 pop r12
4782 pop r11
4783 pop r10
4784 pop r9
4785 pop r8
4786 pop rsi
4787 pop rdi
4788 pop rbp
4789 pop rdx
4790 pop rcx
4791 pop rbx
4792 pop rax
4793 %endmacro
4794 ;-----------------------------------------------------------------------------
4795
4796 ;-----------------------------------------------------------------------------
4797 ; x64 sys calls
4798 %define SYS_BRK 12
4799 %define SYS_EXIT 60
4800 %define SYS_EXIT_GROUP 231
4801 %define SYS_READ 0
4802 %define SYS_WRITE 1
4803 %define SYS_OPEN 2
4804 %define SYS_CLOSE 3
4805 %define SYS_FSTAT 5
4806 %define SYS_MMAP 9
4807 %define SYS_MUNMAP 11
4808 %define SYS_NANOSLEEP 35
4809 %define SYS_TIME 201
4810
4811 ; For threadism:
4812 %define SYS_CLONE 56
4813
4814 ; For tty cure:
4815 %define SYS_IOCTL 16
4816
4817 ; For sys_mmap
4818 %define PROT_READ 1
4819 %define PROT_WRITE 2
4820 %define MAP_PRIVATE 2
4821
4822 ; Output fd's:
4823 %define STDOUT 1
4824 %define STDERR 2
4825 ;-----------------------------------------------------------------------------
4826 ; For threadism:
4827 ;; sched.h
4828 %define CLONE_VM 0x00000100
4829 %define CLONE_FS 0x00000200
4830 %define CLONE_FILES 0x00000400
4831 %define CLONE_SIGHAND 0x00000800
4832 %define CLONE_PARENT 0x00008000
4833 %define CLONE_THREAD 0x00010000
4834 %define CLONE_IO 0x80000000
4835
4836 ;; sys/mman.h
4837 %define MAP_GROWSDOWN 0x0100
4838 %define MAP_ANONYMOUS 0x0020
4839 %define MAP_PRIVATE 0x0002
4840 %define PROT_READ 0x1
4841 %define PROT_WRITE 0x2
4842 %define PROT_EXEC 0x4
4843
4844 %define THREAD_FLAGS \
4845 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | \
4846 CLONE_THREAD | CLONE_IO
4847
4848 ;-----------------------------------------------------------------------------
4849 ; Pill for linux's tty buffering retardation
4850 %define ICANON 2
4851 %define ECHO 8
4852 %define TCGETS 21505 ; to read back the termios config
4853 %define TCPUTS 21508 ; to set the termios config
4854 ;-----------------------------------------------------------------------------
4855
4856 ;-----------------------------------------------------------------------------
4857 ; For output of sys_fstat
4858 struc statbuf
4859 .st_dev resq 1
4860 .st_ino resq 1
4861 .st_nlink resq 1
4862 .st_mode resd 1
4863 .st_uid resd 1
4864 .st_gid resd 1
4865 .__pad0 resd 1
4866 .st_rdev resq 1
4867 .st_size resq 1 ; file size in bytes
4868 .st_blksize resq 1
4869 .st_blocks resq 1
4870 .st_atime resq 1
4871 .st_atime_nsec resq 1
4872 .st_mtime resq 1
4873 .st_mtime_nsec resq 1
4874 .st_ctime resq 1
4875 .st_ctime_nsec resq 1
4876 .__unused resq 3
4877 .size
4878 endstruc
4879 ;-----------------------------------------------------------------------------
4880
4881 ;-----------------------------------------------------------------------------
4882 ;; State
4883 ;-----------------------------------------------------------------------------
4884 section .bss
4885 linux_epoch resq 1 ; for _Get_Epoch_Time
4886 ;-----------------------------------------------------------------------------
4887
4888 section .text
4889
4890 ;-----------------------------------------------------------------------------
4891 ; For spawning slave threads:
4892 ;-----------------------------------------------------------------------------
4893 _Create_Thread:
4894 push rdi
4895 ;; Allocate stack for the new thread:
4896 mov rdi, 0
4897 mov rsi, SLAVE_STACK_SIZE
4898 mov rdx, PROT_WRITE | PROT_READ
4899 mov r10, MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN
4900 mov rax, SYS_MMAP
4901 syscall ; invoke mmap
4902 ;; Verify whether we actually got our memory:
4903 cmp rax, 0
4904 jg .ok
4905 ;; ... if not:
4906 EGGOG "Could not allocate memory for slave stack!"
4907 .ok: ;; we got the memory;
4908 ;; Actually spawn the thread:
4909 lea rsi, [rax + SLAVE_STACK_SIZE - 8]
4910 pop qword [rsi]
4911 mov rdi, THREAD_FLAGS
4912 mov rax, SYS_CLONE
4913 syscall
4914 ret
4915 ;-----------------------------------------------------------------------------
4916
4917 ;-----------------------------------------------------------------------------
4918 ; Get Epoch Time from OS. Return in RDX.
4919 ;-----------------------------------------------------------------------------
4920 _Get_Epoch_Time:
4921 PUSHA
4922 mov rax, SYS_TIME ; sys_time
4923 mov rdi, linux_epoch ; where it will be written
4924 syscall ; invoke the call
4925 POPA
4926 mov rdx, qword [linux_epoch] ; return all 64 bits of epoch time
4927 ret
4928 ;-----------------------------------------------------------------------------
4929
4930 ;-----------------------------------------------------------------------------
4931 ; 'NanoSleep' (rax : pointer to TS structure)
4932 ;-----------------------------------------------------------------------------
4933 _Nano_Sleep:
4934 mov rdi, rax
4935 mov rax, SYS_NANOSLEEP ; nanosleep
4936 xor rsi, rsi
4937 syscall ; Invoke sleep
4938 ret
4939 ;-----------------------------------------------------------------------------
4940
4941 ;-----------------------------------------------------------------------------
4942 ; Terminate Current Thread Only
4943 ;-----------------------------------------------------------------------------
4944 _Stop:
4945 mov rax, SYS_EXIT ; Terminate (current thread only)
4946 mov rdi, 0 ; exit code (always 0, for now)
4947 syscall
4948 ;; no more after this, we're through
4949 ;-----------------------------------------------------------------------------
4950
4951 ;-----------------------------------------------------------------------------
4952 ; Hard Stop (kill self and all child threads)
4953 ;-----------------------------------------------------------------------------
4954 _Hard_Stop:
4955 mov rax, SYS_EXIT_GROUP ; Terminate Master and all slaves
4956 mov rdi, 0 ; exit code (always 0, for now)
4957 syscall
4958 ;; no more after this, we're through
4959 ;-----------------------------------------------------------------------------
-
+ 8F9465318A06392DE5A881B9E47B5912A206B79803F64169B63448F42CDA7123180F42CC90836DAFEE0612015C624E9DF583C7CEAAD80895218CE5B1673F22F0
m/os/linux_io.asm
(0 . 0)(1 . 160)
4964 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4965 ;; ;;
4966 ;; This file is part of 'M', a MIPS system emulator. ;;
4967 ;; ;;
4968 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
4969 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
4970 ;; ;;
4971 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
4972 ;; distribute this software ; Should you use this software for any purpose, ;;
4973 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
4974 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
4975 ;; continue doing so for the indefinite future. In any case, please ;;
4976 ;; always : read and understand any software ; verify any PGP signatures ;;
4977 ;; that you use - for any purpose. ;;
4978 ;; ;;
4979 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
4980 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4981
4982
4983 ;-----------------------------------------------------------------------------
4984 ;; State
4985 ;-----------------------------------------------------------------------------
4986 section .bss
4987 tty resb TTY_Config_size ; Linux tty state
4988 IOBUF resb 1 ; I/O buffer for print
4989 ;-----------------------------------------------------------------------------
4990
4991 ;----------------------------------------------------------------------------
4992 ;; TTY State Storage
4993 struc TTY_Config
4994 ;; Shell's old tty config (restore on quit) :
4995 .old_tty resb 12
4996 .old_lflag resb 4
4997 .old_brest resb 44
4998 ;; Modified tty config (to run with) :
4999 .tty resb 12
5000 .lflag resb 4
5001 .brest resb 44
5002 endstruc
5003 ;----------------------------------------------------------------------------
5004
5005 section .text
5006
5007 ;-----------------------------------------------------------------------------
5008 _Cure_TTY:
5009 ;; Get initial tty state (for restore after quit) :
5010 mov rdx, tty + TTY_Config.old_tty
5011 mov rax, SYS_IOCTL
5012 mov rdi, 0
5013 mov rsi, TCGETS
5014 syscall
5015
5016 ;; Get another copy of initial tty state (to modify) :
5017 mov rdx, tty + TTY_Config.tty
5018 mov rax, SYS_IOCTL
5019 mov rdi, 0
5020 mov rsi, TCGETS
5021 syscall
5022
5023 ;; Switch off linux console 'cooked mode' idiocy:
5024 and dword [tty + TTY_Config.lflag], ~(0xF)
5025
5026 ;; Set the modified tty state:
5027 mov rdx, tty + TTY_Config.tty
5028 mov rax, SYS_IOCTL
5029 mov rdi, 0
5030 mov rsi, TCPUTS
5031 syscall
5032 ret
5033 ;-----------------------------------------------------------------------------
5034 _Uncure_TTY: ;; Set original tty state again:
5035 mov rdx, tty + TTY_Config.old_tty
5036 mov rax, SYS_IOCTL
5037 mov rdi, 0
5038 mov rsi, TCPUTS
5039 syscall
5040 ret
5041 ;-----------------------------------------------------------------------------
5042
5043 ;-----------------------------------------------------------------------------
5044 ; I/O
5045 ;-----------------------------------------------------------------------------
5046 _Write_Char:
5047 PUSHA
5048 mov byte [IOBUF], dl
5049 mov rdx, 1
5050 mov rax, SYS_WRITE
5051 mov rsi, IOBUF
5052 mov rdi, STDOUT
5053 syscall
5054 POPA
5055 ret
5056
5057 ;; return char in IOBUF
5058 _Read_Char_Blocking:
5059 PUSHA
5060 mov rdi, 0 ; STDIN
5061 mov rsi, IOBUF ; where to put
5062 mov rdx, 1 ; read one char
5063 mov rax, 0
5064 syscall
5065 POPA
5066 ret
5067 ;-----------------------------------------------------------------------------
5068
5069 ;-----------------------------------------------------------------------------
5070 ; Transmit string to STDERR. RDX points to length (32bit) after which is text.
5071 ;-----------------------------------------------------------------------------
5072 _Print_Text_STDERR:
5073 PUSHA
5074 mov rdi, STDERR ; Destination
5075 lea rsi, [rdx + 4] ; Start of text
5076 mov rax, SYS_WRITE ; SYS_WRITE
5077 mov edx, dword [edx] ; Length of text
5078 syscall ; Transmit the text to STDERR
5079 POPA
5080 ret
5081 ;-----------------------------------------------------------------------------
5082
5083 ;-----------------------------------------------------------------------------
5084 ; Print hex value of EAX to STDOUT.
5085 ;-----------------------------------------------------------------------------
5086 ; _Dump_Byte:
5087 ; PUSHA
5088 ; mov ebp, eax
5089 ; shr eax, 4
5090 ; call _dig
5091 ; mov eax, ebp
5092 ; call _dig
5093 ; POPA
5094 ; ret
5095
5096 ; _Dump_EAX:
5097 ; PUSHA
5098 ; mov ebp, eax
5099 ; mov ebx, 28
5100 ; _do_dig:
5101 ; mov eax, ebp
5102 ; mov ecx, ebx
5103 ; shr eax, cl
5104 ; call _dig
5105 ; sub ebx, 4
5106 ; jnc _do_dig
5107 ; POPA
5108 ; ret
5109 ; _dig:
5110 ; and eax, 0xF
5111 ; mov rsi, _digits
5112 ; add rsi, rax
5113 ; mov rdx, 0x1
5114 ; mov rax, SYS_WRITE
5115 ; mov rdi, STDOUT
5116 ; syscall
5117 ; ret
5118 ;-----------------------------------------------------------------------------
5119
5120 section .rodata
5121
5122 ; _linefeed: db 0xA, 0
5123 _digits: db "0123456789abcdef", 0
-
+ 6AD0018398EFC679130DB6E4ABDF4082D644BCBB623CE66C49899053B0A032A27FF1DE0702EFECD0A5BF6718ADFBDF9F1C38B7E2F1EFAE34CFAF0258E0731F8D
m/ram.asm
(0 . 0)(1 . 420)
5128 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5129 ;; ;;
5130 ;; This file is part of 'M', a MIPS system emulator. ;;
5131 ;; ;;
5132 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
5133 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
5134 ;; ;;
5135 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
5136 ;; distribute this software ; Should you use this software for any purpose, ;;
5137 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
5138 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
5139 ;; continue doing so for the indefinite future. In any case, please ;;
5140 ;; always : read and understand any software ; verify any PGP signatures ;;
5141 ;; that you use - for any purpose. ;;
5142 ;; ;;
5143 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
5144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5145
5146 ;-----------------------------------------------------------------------------
5147 ;; State
5148 ;-----------------------------------------------------------------------------
5149 section .bss
5150 M resb 8 ; Addr mmap'd M (message) buffer
5151 Mbytes resb 8 ; Length of image (bytes)
5152 RAMbytes resb 8 ; Total size of RAM (bytes)
5153 ;-----------------------------------------------------------------------------
5154
5155 section .text
5156
5157 ;-----------------------------------------------------------------------------
5158 ; Jump if register value resides in given range
5159 ;-----------------------------------------------------------------------------
5160 %macro JMP_If_In 4 ; %1: register, %2: r.bottom, %3: r.top, %4: dest.
5161 cmp %1, %3 ; Compare register to TOP of range
5162 ja %%nope ; If above top -- skip.
5163 cmp %1, %2 ; Compare register to BOTTOM of range
5164 jb %%nope ; If below bottom -- skip.
5165 jmp %4 ; ... Else, register is in the range, and jump.
5166 %%nope
5167 %endmacro
5168 ;-----------------------------------------------------------------------------
5169
5170 ;-----------------------------------------------------------------------------
5171 ; Allocate RAM:
5172 ;-----------------------------------------------------------------------------
5173 _ram_allocate:
5174 ;; Allocate memory for sim RAM:
5175 mov rax, SYS_MMAP
5176 xor r9, r9 ; offset=0
5177 xor r8, r8
5178 mov r10, MAP_PRIVATE | MAP_ANONYMOUS
5179 mov rdx, PROT_READ | PROT_WRITE
5180 mov rsi, [RAMbytes] ; # of bytes to allocate
5181 xor rdi, rdi ; os will give addr
5182 syscall ; invoke mmap
5183 ;; Verify whether we actually got our memory:
5184 cmp rax, 0
5185 jg _mmap_ok
5186 ;; ... if not:
5187 EGGOG "Could not allocate memory for sim RAM!"
5188 _mmap_ok: ;; we got the memory;
5189 ret
5190 ;-----------------------------------------------------------------------------
5191
5192 ;-----------------------------------------------------------------------------
5193 ; Free RAM:
5194 ;-----------------------------------------------------------------------------
5195 _ram_deallocate:
5196 mov rax, SYS_MUNMAP
5197 mov rsi, [RAMbytes]
5198 mov rdi, [M]
5199 syscall ; munmap(M, Mbytes)
5200 ret
5201 ;-----------------------------------------------------------------------------
5202
5203 ;-----------------------------------------------------------------------------
5204 ; Init RAM:
5205 ;-----------------------------------------------------------------------------
5206 _ram_init:
5207 mov RAM_Floor, [M] ; Set 'floor' of RAM
5208 mov RAM_Ceiling, RAM_Floor ; 'ceiling'
5209 add RAM_Ceiling, [RAMbytes]; ... size of the mmap
5210 ;; TODO: test for unaligned floor or ceiling
5211 ret
5212 ;-----------------------------------------------------------------------------
5213
5214 ;-----------------------------------------------------------------------------
5215 ; Translate_Address : virtual address in eax; output (physical addr) in eax
5216 ;-----------------------------------------------------------------------------
5217 align GRAIN, db 0x90
5218 _Virt_To_Phys:
5219 bt eax, 31 ; CF := 31st (top) bit of vAddr
5220 jc _Above_7FFFFFFF ; If 31st bit = 1, kseg 0/1/2; else:
5221 ;; 0x00000000 <= vAddr <= 0x7FFFFFFF (kuseg) :
5222 bt CP0_Status, CP0St_ERL ; CF := CP0St_ERL Flag
5223 jnc _TLB_Lookup ; If ERL = 0: TLB Lookup required; else:
5224 jmp _No_Tlb_Lookup ; pAddr is equal to vAddr, return.
5225 _Above_7FFFFFFF:
5226 bt eax, 30 ; CF := 30th (2nd from top) bt of vAddr
5227 jc _Above_BFFFFFFF ; If 30th bit = 1 : kseg2; else:
5228 ;; 0x80000000 <= vAddr <= 0x9FFFFFFF (kseg0) :
5229 ;; 0xA0000000 <= vAddr <= 0xBFFFFFFF (kseg1) :
5230 and eax, 0x1FFFFFFF ; kseg0 and kseg1: clear top 3 bits,
5231 jmp _No_Tlb_Lookup ; i.e. pAddr := bottom 29 bts of vAddr.
5232 _Above_BFFFFFFF: ;; 0xC0000000 <= vAddr <= 0xFFFFFFFF (kseg2) :
5233 bt CP0_Status, CP0St_UM ; CF := CP0St_UM Flag
5234 jnc _TLB_Lookup ; If UM = 0: K. Mode, so do TLB; else:
5235 test CP0_Status, (1 << CP0St_EXL) | (1 << CP0St_ERL) ; EXL or ERL
5236 jnz _TLB_Lookup ; If EXL && ERL, K. Mode, do TLB
5237 ;; Else: vAddr is in kseg2, but we are NOT in Kernel Mode:
5238 Flg_Get IsWriting ; Is Writing?
5239 jc _V2P_Eggog_Wr ; If so, we want to set AdES;
5240 _V2P_Eggog_Rd: ; ... otherwise, set AdEL.
5241 SetEXC EXC_AdEL ; Fetch address error.
5242 jmp _V2P_Eggog_Fin ; Proceed to abort.
5243 _V2P_Eggog_Wr:
5244 SetEXC EXC_AdES ; Store address error.
5245 _V2P_Eggog_Fin:
5246 ;; Will go into exception handler instead of back to _Virt_xxx etc
5247 add rsp, 16 ; squelch return to _Virt_xxx and its caller
5248 push _Handle_Exception ; 'return' directly to exc handler.
5249 _No_Tlb_Lookup:
5250 Flg_Off IsWriting ; Consume 'is writing' flag.
5251 ret ; Done.
5252 _TLB_Lookup: ; TLB Lookup Required:
5253 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5254 ;; Save ebx, ecx, edx, AUX, to xmm ;;
5255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5256 movd xmm0, ebx
5257 movd xmm1, ecx
5258 movd xmm2, edx
5259 movd xmm3, AUX
5260 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5261 Flg_Off ExcWasTLBNoMatch ; Clear the ExcWasTLBNoMatch Flag
5262 ;; Get the active ASID:
5263 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
5264 and edx, 0xFF ; edx := edx & 0xFF (get current ASID)
5265 ;; For each slot in table (0 .. 15), attempt lookup
5266 xor AUX, AUX ; Start with the 0-th entry in table
5267 _Lookup_TLB_E:
5268 mov ecx, eax ; ecx := eax (vAddr)
5269 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
5270 shr ecx, 13 ; ecx := ecx >> 13 (get vAddr's Tag)
5271 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
5272 and ebx, TLB_VPN2_Mask ; get VPN2 of this entry
5273 cmp ebx, ecx ; cmp(entry.VPN2, vAddr.tag)
5274 jne _Lookup_TLB_E_Not_Here ; if entry.VPN2 != vAddr.tag: no match
5275 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
5276 bt ebx, TLB_G ; is entry.G = 1?
5277 jc _Lookup_TLB_E_Match ; then match.
5278 shr ebx, TLB_ASID_Shift ; ebx := ebx >> TLB_ASID_Shift
5279 and ebx, TLB_ASID_Mask ; ebx := entry.ASID
5280 cmp ebx, edx ; entry.ASID = current ASID ?
5281 jne _Lookup_TLB_E_Not_Here ; if neither G=1 nor ASID match.
5282 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
5283 _Lookup_TLB_E_Match: ; TLB Match:
5284 bt eax, 12 ; Test odd/even junior bit
5285 jc _Lookup_TLB_E_Match_Odd ; If odd: test V1, D1
5286 _Lookup_TLB_E_Match_Even: ; If even: test V0, D0
5287 lea ecx, TLB_PFN_E(AUX) ; prepare to load even PFN entry
5288 bt ebx, TLB_V0 ; Is entry.V0=1 ?
5289 jnc _Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
5290 bt ebx, TLB_D0 ; Is entry.D0=1 ?
5291 jc _Lookup_TLB_E_Match_Yes ; If entry.D0=1, then Match Yes
5292 jmp _Lookup_TLB_E_Match_Wr ; else, go to 'is writing?'
5293 _Lookup_TLB_E_Match_Odd: ; Odd bit:
5294 lea ecx, TLB_PFN_O(AUX) ; prepare to load odd PFN entry
5295 bt ebx, TLB_V1 ; Is entry.V1=1 ?
5296 jnc _Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
5297 bt ebx, TLB_D1 ; Is entry.D1=1 ?
5298 jc _Lookup_TLB_E_Match_Yes ; If entry.D1=1, then Match Yes
5299 _Lookup_TLB_E_Match_Wr:
5300 Flg_Get IsWriting ; Is Writing?
5301 jnc _Lookup_TLB_E_Match_Yes ; If not writing, go to Match Yes
5302 _Lookup_TLB_E_Dirty: ; ... else, Dirty:
5303 SetEXC EXC_Mod ; Set the EXC_Mod Exception
5304 jmp _Lookup_TLB_E_WriteExtr ; Write the 'extra data' and finish.
5305 _Lookup_TLB_E_Match_Yes: ; This is the 'success' case
5306 mov ebx, dword [ecx] ; Actually load the current PFN entry
5307 and eax, 0xFFF ; vAddr := vAddr & 0xFFF
5308 or eax, ebx ; vAddr := vAddr | entry.PFN[lowbit]
5309 jmp _Lookup_TLB_Done ; vAddr is now correct pAddr, done.
5310 _Lookup_TLB_E_Not_Here: ; try next one in the table, if any
5311 inc AUX ; index := index + 1
5312 cmp AUX, TLB_ENTRIES_COUNT ; see if still in range 0 .. n-1
5313 jb _Lookup_TLB_E ; if in range, go to next entry
5314 ;; ... else:
5315 Flg_On ExcWasTLBNoMatch ; Set the ExcWasTLBNoMatch Flag
5316 ;; ... now drop down into 'invalid' :
5317 _Lookup_TLB_E_Invalid:
5318 Flg_Get IsWriting ; Was Writing?
5319 jc _Lookup_TLB_E_Invalid_W ; If so, we want to set EXC_TLBS
5320 _Lookup_TLB_E_Invalid_R: ; Otherwise, set EXC_TLBL exception
5321 SetEXC EXC_TLBL ; Set the EXC_TLBL Exception
5322 jmp _Lookup_TLB_E_WriteExtr ; Write the 'extra data' and finish.
5323 _Lookup_TLB_E_Invalid_W:
5324 SetEXC EXC_TLBS ; Set the EXC_TLBS Exception
5325 ;; then drop down to 'write extra' :
5326 _Lookup_TLB_E_WriteExtr: ; Write the 'extra data' and finish
5327 mov Sr(CP0_BadVAddr), eax ; CP0_BadVAddr := vAddr
5328 mov ecx, eax ; ecx := vAddr
5329 mov ebx, Sr(CP0_Context) ; ebx := CP0_Context
5330 and ebx, ~0x007FFFFF ; ebx := ebx & ~0x007FFFFF
5331 shr ecx, 9 ; ecx := ecx >> 9
5332 and ecx, 0x007FFFF0 ; ecx := ecx & 0x007FFFF0
5333 or ebx, ecx ; ebx := ebx | ecx
5334 mov Sr(CP0_Context), ebx ; CP0_Context := ebx
5335 mov ecx, eax ; ecx := vAddr
5336 mov ebx, Sr(CP0_EntryHi) ; ebx := CP0_EntryHi
5337 and ebx, 0xFF ; ebx := ebx & 0xFF
5338 and ecx, 0xFFFFE000 ; ecx := ecx & 0xFFFFE000
5339 or ebx, ecx ; ebx := ebx | ecx
5340 mov Sr(CP0_EntryHi), ebx ; CP0_EntryHi := ebx
5341 ;; Will go into exception handler instead of back to _Virt_xxx etc
5342 add rsp, 16 ; squelch return to _Virt_xxx and its caller
5343 push _Handle_Exception ; 'return' directly to exc handler.
5344 ;; and drop into 'done' :
5345 _Lookup_TLB_Done:
5346 Flg_Off IsWriting ; Consume 'is writing' flag.
5347 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5348 ;; Restore ebx, ecx, edx, AUX, from xmm ;;
5349 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5350 movd ebx, xmm0
5351 movd ecx, xmm1
5352 movd edx, xmm2
5353 movd AUX, xmm3
5354 ret
5355 ;-----------------------------------------------------------------------------
5356
5357 ;-----------------------------------------------------------------------------
5358 ; ReadWord - Source Address (Virtual) is EAX; Resulting Word Read is EAX.
5359 ;-----------------------------------------------------------------------------
5360 ; TODO: 1) is the 'unaligned' case in fact physically possible?
5361 ; 2) would go faster if used tmp instead of self-clobbering rax ?
5362 align GRAIN, db 0x90
5363 _Virt_Read_Word:
5364 call _Virt_To_Phys ; Transform vAddr to pAddr
5365 test eax, 0x3 ; Are any of the bottom 2 bits set?
5366 jnz _V_Rd_Word_Unaligned ; If yes, go to eggog. Else:
5367 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5368 ;; If pAddr is in Memory-Mapped Device space:
5369 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Read_Word
5370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5371 add rax, RAM_Floor ; Calculate the target PC RAM addr
5372 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5373 jnb _V_Rd_Word_Hit_Ceiling ; if not below: RAM ceiling eggog!
5374 ;; Address is valid, so load the word:
5375 mov eax, dword [rax] ; eax := dword [rax]
5376 ret ; Done, return with read result in eax.
5377 _V_Rd_Word_Unaligned: ;; TODO: print address
5378 ACHTUNG "Virt_Read_Word: Unaligned Physical Address!"
5379 jmp _V_Rd_Word_Eggog ; Go to eggogology
5380 _V_Rd_Word_Hit_Ceiling: ;; TODO: print address
5381 ACHTUNG "Virt_Read_Word: Hit RAM Ceiling!"
5382 _V_Rd_Word_Eggog:
5383 SetEXC EXC_AdEL ; Fetch address error.
5384 ;; Will go into exception handler instead of back to caller
5385 add rsp, 8 ; squelch return to original caller
5386 push _Handle_Exception ; 'return' directly to exc handler.
5387 ret ; Go there.
5388 ;-----------------------------------------------------------------------------
5389
5390 ;-----------------------------------------------------------------------------
5391 ; WriteWord - Destination Address (Virtual) is EAX; Word to be Written is TMP.
5392 ;-----------------------------------------------------------------------------
5393 ; TODO: 1) is the 'unaligned' case in fact physically possible?
5394 ; 2) would go faster if used tmp instead of self-clobbering rax ?
5395 ; 3) do we need to explicitly zero-extend rax here?
5396 align GRAIN, db 0x90
5397 _Virt_Write_Word:
5398 Flg_On IsWriting ; Tell the translator that we're writing
5399 call _Virt_To_Phys ; Transform vAddr to pAddr
5400 test eax, 0x3 ; Are any of the bottom 2 bits set?
5401 jnz _V_Wr_Word_Unaligned ; If yes, go to eggog. Else:
5402 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5403 ;; If pAddr is in Memory-Mapped Device space:
5404 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Write_Word
5405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5406 add rax, RAM_Floor ; Calculate the target PC RAM addr
5407 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5408 jnb _V_Wr_Word_Hit_Ceiling ; if not below: RAM ceiling eggog!
5409 ;; Address is valid, so write the word:
5410 mov dword [rax], TMP ; dword [rax] := TMP
5411 ret ; Done.
5412 _V_Wr_Word_Unaligned: ;; TODO: print address
5413 ACHTUNG "Virt_Write_Word: Unaligned Physical Address!"
5414 jmp _V_Wr_Word_Eggog
5415 _V_Wr_Word_Hit_Ceiling: ;; TODO: print address
5416 ACHTUNG "Virt_Write_Word: Hit RAM Ceiling!"
5417 _V_Wr_Word_Eggog:
5418 SetEXC EXC_AdES ; Store address error.
5419 ;; Will go into exception handler instead of back to caller
5420 add rsp, 8 ; squelch return to original caller
5421 push _Handle_Exception ; 'return' directly to exc handler.
5422 ret ; Go there.
5423 ;-----------------------------------------------------------------------------
5424
5425 ;-----------------------------------------------------------------------------
5426 ; ReadByte - Source Address (Virtual) is EAX; Resulting Byte Read is EAX.
5427 ;-----------------------------------------------------------------------------
5428 align GRAIN, db 0x90
5429 _Virt_Read_Byte:
5430 call _Virt_To_Phys ; Transform vAddr to pAddr
5431 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5432 ;; If pAddr is in Memory-Mapped Device space:
5433 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Read_Byte
5434 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5435 %ifdef LITTLE_ENDIAN
5436 ;; little -- do nothing
5437 %else
5438 ;; big -- flip :
5439 xor eax, 0x3 ; Flip the 3 unalignment bits.
5440 %endif
5441 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5442 add rax, RAM_Floor ; Calculate the target PC RAM addr
5443 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5444 jnb _V_Rd_Byte_Hit_Ceiling ; if not below: RAM ceiling eggog!
5445 ;; Address is valid, so proceed to load:
5446 movzx ax, byte [rax] ; ax := byte [rax]
5447 and eax, 0xFF ; keep only bottom byte
5448 ret ; Done, return with read result in eax.
5449 _V_Rd_Byte_Hit_Ceiling:
5450 ACHTUNG "Virt_Read_Byte: Hit RAM Ceiling!" ;; TODO: print address
5451 SetEXC EXC_AdEL ; Fetch address error.
5452 ;; Will go into exception handler instead of back to caller
5453 add rsp, 8 ; squelch return to original caller
5454 push _Handle_Exception ; 'return' directly to exc handler.
5455 ret ; Go there.
5456 ;-----------------------------------------------------------------------------
5457
5458 ;-----------------------------------------------------------------------------
5459 ; WriteByte - Destination Address (Virtual) is EAX; Byte to be Written is DL.
5460 ;-----------------------------------------------------------------------------
5461 align GRAIN, db 0x90
5462 _Virt_Write_Byte:
5463 Flg_On IsWriting ; Tell the translator that we're writing
5464 call _Virt_To_Phys ; Transform vAddr to pAddr
5465 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5466 ;; If pAddr is in Memory-Mapped Device space:
5467 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Write_Byte
5468 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5469 %ifdef LITTLE_ENDIAN
5470 ;; little -- do nothing
5471 %else
5472 ;; big -- flip :
5473 xor eax, 0x3 ; Flip the 3 unalignment bits.
5474 %endif
5475 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5476 add rax, RAM_Floor ; Calculate the target PC RAM addr
5477 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5478 jnb _V_Wr_Byte_Hit_Ceiling ; if not below: RAM ceiling eggog!
5479 ;; Address is valid, so write the byte:
5480 mov byte [rax], DL ; dword [rax] := TMP
5481 ret ; Done.
5482 _V_Wr_Byte_Hit_Ceiling:
5483 ACHTUNG "Virt_Write_Byte: Hit RAM Ceiling!" ;; TODO: print address
5484 SetEXC EXC_AdES ; Store address error.
5485 ;; Will go into exception handler instead of back to caller
5486 add rsp, 8 ; squelch return to original caller
5487 push _Handle_Exception ; 'return' directly to exc handler.
5488 ret ; Go there.
5489 ;-----------------------------------------------------------------------------
5490
5491 ;-----------------------------------------------------------------------------
5492 ; Write TLB Entry at the given index. Index (0 .. 15) is in AUX.
5493 ; Kills eax, ebx, ecx, edx.
5494 ;-----------------------------------------------------------------------------
5495 _write_tlb_entry:
5496 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
5497 mov ecx, edx ; ecx := edx
5498 shr ecx, 13 ; ecx := ecx >> 13 to get VPN2
5499 and edx, TLB_ASID_Mask ; edx := edx & 0xFF to get ASID
5500 shl edx, TLB_ASID_Shift ; edx := edx << 19 to put ASID in place
5501 or ecx, edx ; now we have VPN2 and ASID in ecx
5502 ;; done with edx, can reuse
5503 mov edx, Sr(CP0_EntryLo0) ; edx := CP0_EntryLo0
5504 mov ebx, Sr(CP0_EntryLo1) ; ebx := CP0_EntryLo1
5505 ;; get G:
5506 mov eax, edx ; eax := CP0_EntryLo0
5507 and eax, ebx ; eax := eax & CP0_EntryLo1
5508 and eax, 0x1 ; eax := eax & 1 to get G
5509 shl eax, TLB_G ; move G bit into position
5510 or ecx, eax ; ecx := ecx | eax to put in G bit
5511 ;; now ecx contains VPN2, ASID, G
5512 ;; Get V0 from CP0_EntryLo0 and put in ecx where belongs:
5513 mov eax, edx ; eax := CP0_EntryLo0
5514 and eax, 0x2 ; eax := eax & 0x2 to get V0 bit
5515 shl eax, (TLB_V0 - 1) ; put V0 bit in position
5516 or ecx, eax ; ecx := ecx | eax to put in V0 bit
5517 ;; Get D0 from CP0_EntryLo0 and put in ecx where belongs:
5518 mov eax, edx ; eax := CP0_EntryLo0
5519 and eax, 0x4 ; eax := eax & 0x4 to get D0 bit
5520 shl eax, (TLB_D0 - 2) ; put D0 bit in position
5521 or ecx, eax ; ecx := ecx | eax to put in D0 bit
5522 ;; Get V1 from CP0_EntryLo1 and put in ecx where belongs:
5523 mov eax, ebx ; eax := CP0_EntryLo1
5524 and eax, 0x2 ; eax := eax & 0x2 to get V1 bit
5525 shl eax, (TLB_V1 - 1) ; put V1 bit in position
5526 or ecx, eax ; ecx := ecx | eax to put in V1 bit
5527 ;; Get D1 from CP0_EntryLo1 and put in ecx where belongs:
5528 mov eax, ebx ; eax := CP0_EntryLo1
5529 and eax, 0x4 ; eax := eax & 0x4 to get D1 bit
5530 shl eax, (TLB_D1 - 2) ; put D1 bit in position
5531 or ecx, eax ; ecx := ecx | eax to put in D1 bit
5532 ;; Write the TLB entry to the given index (in AUX) :
5533 and AUX, 0xF ; Index of TLB entry is bottom 4 bits
5534 mov TLB_E(AUX), ecx ; Write TLB entry in ecx to n-th slot.
5535 ;; Transform CP0_EntryLo0 (edx) into PFN0:
5536 shr edx, 6
5537 and edx, 0xFFFFF
5538 shl edx, 12
5539 ;; Transform CP0_EntryLo1 (ebx) into PFN1:
5540 shr ebx, 6
5541 and ebx, 0xFFFFF
5542 shl ebx, 12
5543 ;; Store PFN:
5544 mov TLB_PFN_E(AUX), edx ; Store PFN0
5545 mov TLB_PFN_O(AUX), ebx ; Store PFN1
5546 ret ; Done.
5547 ;-----------------------------------------------------------------------------
-
+ 1F88A9E52105C1F6C33BA0F19E67C4158E5DF93EA374F9F7774C89D126A0714C830712EEA555FF51881A26D2BE47861CDDCD254395467770D2C34EF60D02C524
m/shutdown.asm
(0 . 0)(1 . 31)
5552 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5553 ;; ;;
5554 ;; This file is part of 'M', a MIPS system emulator. ;;
5555 ;; ;;
5556 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
5557 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
5558 ;; ;;
5559 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
5560 ;; distribute this software ; Should you use this software for any purpose, ;;
5561 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
5562 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
5563 ;; continue doing so for the indefinite future. In any case, please ;;
5564 ;; always : read and understand any software ; verify any PGP signatures ;;
5565 ;; that you use - for any purpose. ;;
5566 ;; ;;
5567 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
5568 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5569
5570 section .text
5571
5572 ;-----------------------------------------------------------------------------
5573 _shutdown:
5574 call _Phys_Devices_Shutdown ; Initiate shutdown of all slaves
5575 call _ram_deallocate ; free memory
5576
5577 _exit:
5578 jmp _Hard_Stop
5579
5580 _exit_thread: ;; Thread exits go here
5581 jmp _Stop
5582 ;-----------------------------------------------------------------------------