aboutsummaryrefslogtreecommitdiff
path: root/snug-clean/src/MIPS/MIPS32.icl
blob: 655219de49a2bb7fce48f02c5763accaa92b27d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
implementation module MIPS.MIPS32

import StdEnv

import Text

instance toString Line
where
	toString (StartSection s) = "\t." +++ s
	toString (Align i) = "\t.align\t" +++ toString i
	toString (Label l) = l +++ ":"
	toString (Global l) = "\t.globl\t" +++ l
	toString (Instr i) = "\t" +++ toString i
	toString (RawByte i) = "\t.byte\t" +++ toString i
	toString (RawWord i) = "\t.word\t" +++ toString i
	toString (RawWordLabel l) = "\t.word\t" +++ l
	toString (RawAscii s) = concat3 "\t.ascii\t\"" s "\"" // TODO: escaping

instance toString Instruction
where
	toString (LoadByte signed rt offset base) =
		memInstrS (if (signed=:Signed) "lb" "lbu") rt (checkOffset offset) base
	toString (LoadHalfword signed rt offset base) =
		memInstrS (if (signed=:Signed) "lh" "lhu") rt (checkOffset offset) base
	toString (LoadWord rt offset base) =
		memInstrS "lw" rt (checkOffset offset) base
	toString (StoreByte rt offset base) =
		memInstrS "sb" rt (checkOffset offset) base
	toString (StoreHalfword rt offset base) =
		memInstrS "sh" rt (checkOffset offset) base
	toString (StoreWord rt offset base) =
		memInstrS "sw" rt (checkOffset offset) base

	toString (AddImmediate signed rt rs imm) =
		immediateInstrS (if (signed=:Signed) "addi" "addiu") rt rs (checkImmediate signed imm)
	toString (AndImmediate rt rs imm) =
		immediateInstrS "andi" rt rs (checkImmediate Unsigned imm)
	toString (LoadUpperImmediate rt imm) =
		concat ["lui\t",toString rt,",",toString (checkImmediate Unsigned imm)]
	toString (OrImmediate rt rs imm) =
		immediateInstrS "ori" rt rs (checkImmediate Unsigned imm)
	toString (XorImmediate rt rs imm) =
		immediateInstrS "xori" rt rs (checkImmediate Unsigned imm)

	toString (AddWord signed rd rs rt) =
		threeRegInstrS (if (signed=:Signed) "add" "addu") rd rs rt
	toString (AndWord rd rs rt) =
		threeRegInstrS "and" rd rs rt
	toString (NorWord rd rs rt) =
		threeRegInstrS "nor" rd rs rt
	toString (OrWord rd rs rt) =
		threeRegInstrS "or" rd rs rt
	toString (SubWord signed rd rs rt) =
		threeRegInstrS (if (signed=:Signed) "sub" "subu") rd rs rt
	toString (XorWord rd rs rt) =
		threeRegInstrS "xor" rd rs rt

	toString (Jump link target) =
		instr +++ toString target
	where
		instr = case (link, target) of
			(NoLink, Direct _) -> "j\t"
			(Link, Direct _) -> "jal\t"
			(NoLink, Register _) -> "jr\t"
			(Link, Register _) -> "jalr\t"
	toString (BranchOn1 (BCGeZero link) rs offset) =
		branch1InstrS (if (link=:Link) "bgezal" "bgez") rs (checkOffset offset)
	toString (BranchOn1 BCGtZero rs offset) =
		branch1InstrS "bgtz" rs (checkOffset offset)
	toString (BranchOn1 BCLeZero rs offset) =
		branch1InstrS "blez" rs (checkOffset offset)
	toString (BranchOn1 (BCLtZero link) rs offset) =
		branch1InstrS (if (link=:Link) "bltzal" "bltz") rs (checkOffset offset)
	toString (BranchOn2 cond rs rt offset) =
		immediateInstrS (if (cond=:BCEq) "beq" "bne") rs rt (Immediate (checkOffset offset))

	toString (Break arg) =
		"break\t" +++ toString arg
	toString (Syscall arg) =
		"syscall\t" +++ toString arg

	toString (LoadAddress rd imm) =
		concat4 "la\t" (toString rd) "," (toString imm)
	toString Nop =
		"nop"

instance toString JumpTarget
where
	toString (Direct imm)
		= toString imm
	toString (Register r)
		= toString r

instance toString Immediate
where
	toString (Immediate i)
		= toString i
	toString (Address offset label)
		| offset == 0
			= label
		| offset > 0
			= concat3 label "+" (toString offset)
			= concat3 label "-" (toString offset)

memInstrS :: !String !Register !Offset !Base -> String
memInstrS opcode rt 0 base = concat [opcode,"\t",toString rt,",(",toString base,")"]
memInstrS opcode rt offset base = concat [opcode,"\t",toString rt,",",toString offset,"(",toString base,")"]

immediateInstrS :: !String !TargetRegister !SourceRegister !Immediate -> String
immediateInstrS opcode rt rs imm = concat [opcode,"\t",toString rt,",",toString rs,",",toString imm]

threeRegInstrS :: !String !DestinationRegister !SourceRegister !TargetRegister -> String
threeRegInstrS opcode rd rs rt = concat [opcode,"\t",toString rd,",",toString rs,",",toString rt]

branch1InstrS :: !String !SourceRegister !Offset -> String
branch1InstrS opcode rs offset = concat [opcode,"\t",toString rs,",",toString offset]

instance toString Register
where
	toString reg = toString` (checkReg reg)
	where
		/* Sorted by estimated frequency for efficiency */
		toString` (T n) = "$t" +++ toString n
		toString` (S n) = "$s" +++ toString n
		toString` (A n) = "$a" +++ toString n
		toString` R0 = "$0"
		toString` GP = "$gp"
		toString` SP = "$sp"
		toString` FP = "$fp"
		toString` RA = "$ra"
		toString` AT = "$at"
		toString` V0 = "$v0"
		toString` V1 = "$v1"
		toString` K0 = "$k0"
		toString` K1 = "$k1"

checkReg :: !Register -> Register
checkReg (T n) | not (0 <= n && n <= 9)
	= abort ("non-existing register $t" +++ toString n +++ "\n")
checkReg (S n) | not (0 <= n && n <= 7)
	= abort ("non-existing register $s" +++ toString n +++ "\n")
checkReg (A n) | not (0 <= n && n <= 3)
	= abort ("non-existing register $a" +++ toString n +++ "\n")
checkReg reg
	= reg

checkOffset :: !Int -> Int
checkOffset offset
	| 0 <= offset && offset <= 0x7fff
		= offset
	| offset >= -0x8000
		= offset bitand 0xffff
		= abort ("offset " +++ toString offset +++ " out of bounds\n")

checkImmediate :: !Signedness !Immediate -> Immediate
checkImmediate Signed (Immediate imm)
	| 0 <= imm && imm <= 0x7fff
		= Immediate imm
	| imm >= -0x8000
		= Immediate (imm bitand 0xffff)
		= abort ("signed immediate " +++ toString imm +++ " out of bounds\n")
checkImmediate Unsigned (Immediate imm)
	| 0 <= imm && imm <= 0xffff
		= Immediate imm
		= abort ("unsigned immediate " +++ toString imm +++ " out of bounds\n")