Skip to content

Commit 852e6a0

Browse files
Tons of fixes & new directives + functions. Now able to initialize DOOM.
1 parent a3495c6 commit 852e6a0

9 files changed

Lines changed: 386 additions & 54 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ main.*
88
!main.go
99
platform.info
1010
profile.*
11+
build

compiler/compilation.go

Lines changed: 167 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package compiler
33
import (
44
_ "embed"
55
"fmt"
6+
"strconv"
67
"strings"
78

89
log "github.com/sirupsen/logrus"
@@ -254,15 +255,17 @@ var instructions = map[string]func(*OutputWriter, AssemblyCommand){
254255
"bexti": bexti,
255256
}
256257
var directives = map[string]func(*OutputWriter, []string){
257-
".asciz": asciz,
258-
".string": asciz,
259-
".base64": base64data,
260-
".quad": quad,
261-
".word": word,
262-
".byte": byte_,
263-
".half": half,
264-
".zero": zero,
265-
".set": set,
258+
".asciz": asciz,
259+
".string": asciz,
260+
".base64": base64data,
261+
".quad": quad,
262+
".word": word,
263+
".byte": byte_,
264+
".half": half,
265+
".zero": zero,
266+
".align": align,
267+
".p2align": align,
268+
".set": set,
266269
}
267270

268271
/* main */
@@ -286,19 +289,150 @@ func CompileInstruction(writer *OutputWriter, command AssemblyCommand) {
286289
label(writer, command)
287290
}
288291
}
292+
func normalizeSection(name string) string {
293+
name = strings.Split(name, ",")[0]
294+
name = strings.Trim(name, "\"")
295+
if strings.HasPrefix(name, ".rodata") {
296+
return ".rodata"
297+
}
298+
if strings.HasPrefix(name, ".sdata") {
299+
return ".sdata"
300+
}
301+
if strings.HasPrefix(name, ".data") {
302+
return ".data"
303+
}
304+
if strings.HasPrefix(name, ".sbss") {
305+
return ".sbss"
306+
}
307+
if strings.HasPrefix(name, ".bss") {
308+
return ".bss"
309+
}
310+
if strings.HasPrefix(name, ".text") {
311+
return ".text"
312+
}
313+
return ".rodata"
314+
}
315+
289316
func BeforeCompilation(writer *OutputWriter) {
317+
/* Pass 1: Collect all labels into MemoryMap */
318+
tempMaxPC := 1
319+
var pendingLabels []string
320+
321+
sectionPointers := map[string]int32{
322+
".rodata": 1024,
323+
".data": 1024 * 1024, // 1MB
324+
".sdata": 2 * 1024 * 1024, // 2MB
325+
".bss": 3 * 1024 * 1024, // 3MB
326+
".sbss": 4 * 1024 * 1024, // 4MB
327+
".text": 5 * 1024 * 1024, // 5MB
328+
}
329+
currentSection := ".text"
330+
331+
// Provide dummy allocations for common newlib/C externs
332+
writer.MemoryMap["_impure_ptr"] = 16
333+
writer.MemoryMap["_ctype_"] = 32
334+
335+
for i := range writer.Commands {
336+
if writer.Commands[i].Type == Label {
337+
labelName := writer.Commands[i].Name
338+
pendingLabels = append(pendingLabels, labelName)
339+
writer.MemoryMap[labelName] = tempMaxPC // default to current MaxPC
340+
} else if writer.Commands[i].Type == Instruction && writer.Commands[i].Name != "" {
341+
for _, l := range pendingLabels {
342+
writer.MemoryMap[l] = tempMaxPC
343+
}
344+
pendingLabels = nil
345+
tempMaxPC++
346+
} else if writer.Commands[i].Type == Directive {
347+
attributeComponents := ReadDirective(writer.Commands[i].Name)
348+
attributeName := attributeComponents[0]
290349

291-
/* load directives */
350+
if attributeName == ".section" || attributeName == ".text" || attributeName == ".data" || attributeName == ".bss" || attributeName == ".sdata" || attributeName == ".sbss" {
351+
sec := attributeName
352+
if attributeName == ".section" && len(attributeComponents) > 1 {
353+
sec = attributeComponents[1]
354+
}
355+
currentSection = normalizeSection(sec)
356+
continue
357+
}
358+
359+
tempMemPtr := sectionPointers[currentSection]
360+
361+
for _, l := range pendingLabels {
362+
writer.MemoryMap[l] = int(tempMemPtr)
363+
}
364+
pendingLabels = nil
365+
366+
// Some directives increment MemoryDevelopmentPointer
367+
if attributeName == ".asciz" || attributeName == ".string" {
368+
data, _ := UnescapeDirectiveString(attributeComponents[1])
369+
tempMemPtr += int32(len(data) + 1)
370+
} else if attributeName == ".word" {
371+
tempMemPtr += 4
372+
} else if attributeName == ".half" {
373+
tempMemPtr += 2
374+
} else if attributeName == ".byte" {
375+
tempMemPtr += 1
376+
} else if attributeName == ".quad" {
377+
tempMemPtr += 8
378+
} else if attributeName == ".zero" {
379+
size, _ := strconv.Atoi(attributeComponents[1])
380+
tempMemPtr += int32(size)
381+
} else if attributeName == ".align" || attributeName == ".p2align" {
382+
pow, _ := strconv.Atoi(attributeComponents[1])
383+
alignSize := int32(1 << pow)
384+
rem := tempMemPtr % alignSize
385+
if rem != 0 {
386+
tempMemPtr += alignSize - rem
387+
}
388+
} else if attributeName == ".set" {
389+
symName := attributeComponents[1]
390+
if len(attributeComponents) >= 3 {
391+
if attributeComponents[2] == "." && len(attributeComponents) >= 5 {
392+
offset, _ := strconv.Atoi(attributeComponents[4])
393+
if attributeComponents[3] == "+" {
394+
writer.MemoryMap[symName] = int(tempMemPtr) + offset
395+
} else if attributeComponents[3] == "-" {
396+
writer.MemoryMap[symName] = int(tempMemPtr) - offset
397+
}
398+
} else {
399+
val, err := strconv.Atoi(attributeComponents[2])
400+
if err == nil {
401+
writer.MemoryMap[symName] = val
402+
} else {
403+
if existingAddr, ok := writer.MemoryMap[attributeComponents[2]]; ok {
404+
writer.MemoryMap[symName] = existingAddr
405+
}
406+
}
407+
}
408+
}
409+
}
410+
411+
sectionPointers[currentSection] = tempMemPtr
412+
}
413+
}
414+
415+
/* Pass 2: Actually process directives and write init() function */
292416
WriteIndentedString(writer, "function init(): ()\n")
293417
writer.Depth++
294418
WriteIndentedString(writer, "reset_registers()\n")
295419

296-
/* pre-read the code, and write directive to top */
420+
sectionPointers = map[string]int32{
421+
".rodata": 1024,
422+
".data": 1024 * 1024,
423+
".sdata": 2 * 1024 * 1024,
424+
".bss": 3 * 1024 * 1024,
425+
".sbss": 4 * 1024 * 1024,
426+
".text": 5 * 1024 * 1024,
427+
}
428+
currentSection = ".text"
429+
writer.MemoryDevelopmentPointer = sectionPointers[currentSection]
430+
297431
for i := range writer.Commands {
298432
if writer.Commands[i].Type == Label {
299433
writer.CurrentLabel = &writer.Commands[i]
300434
writer.Commands[i].Ignore = true
301-
writer.PendingData = PendingData{} // reset so first directive under this label always saves pointer
435+
writer.PendingData = PendingData{}
302436
}
303437
if writer.Commands[i].Type == Instruction && writer.Commands[i].Name != "" {
304438
if writer.CurrentLabel != nil {
@@ -308,23 +442,42 @@ func BeforeCompilation(writer *OutputWriter) {
308442
if writer.Commands[i].Type == Directive {
309443
attributeComponents := ReadDirective(writer.Commands[i].Name)
310444
attributeName := attributeComponents[0]
445+
446+
if attributeName == ".section" || attributeName == ".text" || attributeName == ".data" || attributeName == ".bss" || attributeName == ".sdata" || attributeName == ".sbss" {
447+
sectionPointers[currentSection] = writer.MemoryDevelopmentPointer
448+
sec := attributeName
449+
if attributeName == ".section" && len(attributeComponents) > 1 {
450+
sec = attributeComponents[1]
451+
}
452+
currentSection = normalizeSection(sec)
453+
writer.MemoryDevelopmentPointer = sectionPointers[currentSection]
454+
continue
455+
}
456+
311457
if _, ok := directives[attributeName]; ok {
312458
directives[attributeName](writer, attributeComponents)
313459
} else if writer.Options.Comments {
314460
WriteIndentedString(writer, "-- ASM DIRECTIVE: %s\n", writer.Commands[i].Name)
315461
}
316462
}
317463
}
464+
sectionPointers[currentSection] = writer.MemoryDevelopmentPointer
465+
466+
/* reset MaxPC for second pass */
467+
writer.MaxPC = 1
318468

319469
/* finish loading directives */
320470
WriteIndentedString(writer, "PC = %d\n", FindLabelAddress(writer, writer.Options.MainSymbol))
321-
WriteIndentedString(writer, "r3 = (buffer.len(memory) + %d) / 2 -- start at the center after static data\n", writer.MemoryDevelopmentPointer)
471+
WriteIndentedString(writer, "r3 = %d -- start at the center after static data\n", 8 * 1024 * 1024)
322472
WriteIndentedString(writer, "if r3 >= buffer.len(memory) then error(\"Not enough memory\") end\n")
323473
writer.Depth--
324474
WriteIndentedString(writer, "end\n")
325475

326-
/* start code */
476+
log.Infof("Section ends: rodata=%d, data=%d, sdata=%d, bss=%d, sbss=%d, text=%d",
477+
sectionPointers[".rodata"], sectionPointers[".data"], sectionPointers[".sdata"],
478+
sectionPointers[".bss"], sectionPointers[".sbss"], sectionPointers[".text"])
327479
}
480+
328481
func AfterCompilation(writer *OutputWriter) []byte {
329482
AddEnd(writer) // end the current label, if active
330483

compiler/macros.go

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ func label(w *OutputWriter, command AssemblyCommand) {
2323
w.MaxPC++
2424
}
2525

26-
func save_pointer_at(w *OutputWriter, what string, where int32) {
27-
w.MemoryMap[what] = int(where)
28-
}
29-
func save_pointer(w *OutputWriter) {
30-
save_pointer_at(w, w.CurrentLabel.Name, w.MemoryDevelopmentPointer)
31-
}
32-
3326
func asciz(w *OutputWriter, components []string) {
3427
if len(components) < 2 {
3528
return
@@ -50,7 +43,6 @@ func asciz(w *OutputWriter, components []string) {
5043
IRLit(w.MemoryDevelopmentPointer),
5144
IRRawExpr(luauStringExpression(string(dataWithNull)))))
5245

53-
save_pointer(w)
5446
w.MemoryDevelopmentPointer += int32(len(dataWithNull))
5547
}
5648

@@ -64,7 +56,6 @@ func base64data(w *OutputWriter, components []string) {
6456
return
6557
}
6658

67-
save_pointer(w)
6859
for i, b := range decoded {
6960
Emit(w, IRStmtCall(BUFFER_WRITEU8,
7061
IRSymbol(SYM_MEMORY),
@@ -79,11 +70,17 @@ func base64data(w *OutputWriter, components []string) {
7970
func quad(w *OutputWriter, components []string) {
8071
if w.PendingData.Type != PendingDataTypeNumeric {
8172
w.PendingData.Data = strconv.Itoa(int(w.MemoryDevelopmentPointer))
82-
save_pointer(w)
8373
}
8474
w.PendingData.Type = PendingDataTypeNumeric
8575

86-
val, _ := strconv.ParseInt(components[1], 0, 0)
76+
val, err := strconv.ParseInt(components[1], 0, 64)
77+
if err != nil {
78+
if addr, ok := resolveSymbolAddress(w, components[1]); ok {
79+
val = int64(addr)
80+
} else {
81+
log.Errorf("failed to parse or resolve .quad value %q", components[1])
82+
}
83+
}
8784
Emit(w,
8885
IRStmtCall(BUFFER_WRITEI32, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(val&0xFFFFFFFF)),
8986
IRStmtCall(BUFFER_WRITEI32, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer+4), IRLit(val>>32)),
@@ -94,47 +91,67 @@ func quad(w *OutputWriter, components []string) {
9491
func word(w *OutputWriter, components []string) {
9592
if w.PendingData.Type != PendingDataTypeNumeric {
9693
w.PendingData.Data = strconv.Itoa(int(w.MemoryDevelopmentPointer))
97-
save_pointer(w)
9894
}
9995
w.PendingData.Type = PendingDataTypeNumeric
10096

101-
val, _ := strconv.ParseInt(components[1], 0, 0)
97+
val, err := strconv.ParseInt(components[1], 0, 64)
98+
if err != nil {
99+
if addr, ok := resolveSymbolAddress(w, components[1]); ok {
100+
val = int64(addr)
101+
} else {
102+
log.Errorf("failed to parse or resolve .word value %q", components[1])
103+
}
104+
}
102105
Emit(w, IRStmtCall(BUFFER_WRITEI32, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(val)))
103106
w.MemoryDevelopmentPointer += 4
104107
}
105108

106109
func half(w *OutputWriter, components []string) {
107110
if w.PendingData.Type != PendingDataTypeNumeric {
108111
w.PendingData.Data = strconv.Itoa(int(w.MemoryDevelopmentPointer))
109-
save_pointer(w)
110112
}
111113
w.PendingData.Type = PendingDataTypeNumeric
112114

113-
val, _ := strconv.ParseInt(components[1], 0, 0)
115+
val, err := strconv.ParseInt(components[1], 0, 64)
116+
if err != nil {
117+
if addr, ok := resolveSymbolAddress(w, components[1]); ok {
118+
val = int64(addr)
119+
} else {
120+
log.Errorf("failed to parse or resolve .half value %q", components[1])
121+
}
122+
}
114123
Emit(w, IRStmtCall(BUFFER_WRITEI16, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(val)))
115124
w.MemoryDevelopmentPointer += 2
116125
}
117126

118127
func byte_(w *OutputWriter, components []string) { /* byte_ to avoid overlap with the type */
119128
if w.PendingData.Type != PendingDataTypeNumeric {
120129
w.PendingData.Data = strconv.Itoa(int(w.MemoryDevelopmentPointer))
121-
save_pointer(w)
122130
}
123131
w.PendingData.Type = PendingDataTypeNumeric
124132

125133
val, _ := strconv.ParseInt(components[1], 0, 0)
126-
// NOTE: original code used writei16 for .byte — preserved intentionally
127-
Emit(w, IRStmtCall(BUFFER_WRITEI16, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(val)))
134+
Emit(w, IRStmtCall(BUFFER_WRITEU8, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(val&0xFF)))
128135
w.MemoryDevelopmentPointer += 1
129136
}
130137

131138
func zero(w *OutputWriter, components []string) {
132139
size, _ := strconv.ParseInt(components[1], 0, 0)
133-
save_pointer(w)
134140
Emit(w, IRStmtCall(BUFFER_FILL, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(0), IRLit(size)))
135141
w.MemoryDevelopmentPointer += int32(size)
136142
}
137143

144+
func align(w *OutputWriter, components []string) {
145+
pow, _ := strconv.Atoi(components[1])
146+
alignSize := int32(1 << pow)
147+
rem := w.MemoryDevelopmentPointer % alignSize
148+
if rem != 0 {
149+
pad := alignSize - rem
150+
Emit(w, IRStmtCall(BUFFER_FILL, IRSymbol(SYM_MEMORY), IRLit(w.MemoryDevelopmentPointer), IRLit(0), IRLit(pad)))
151+
w.MemoryDevelopmentPointer += pad
152+
}
153+
}
154+
138155
func set(w *OutputWriter, components []string) {
139-
save_pointer_at(w, components[1], w.MemoryDevelopmentPointer)
156+
// handled in compilation.go or not needed for memory layout
140157
}

0 commit comments

Comments
 (0)