Skip to content

Commit 544b297

Browse files
authored
Add operand and replace JNZ JPOS JNEG by JNE JEQ JLT JGT JLTE JGTE - use them to improve the .asm (#46)
* Add operand and replace JNZ JPOS JNEG by JNE JEQ JLT JGT JLTE JGTE * Use the new instructions to simplify cat.asm * Improve fact.asm too to handle bad input while at it * fix ai bug in code replacement, also use JEQ * make sure we don't pow infinite loop
1 parent 18ed280 commit 544b297

File tree

14 files changed

+202
-90
lines changed

14 files changed

+202
-90
lines changed

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ cat-test: vm grol_cvm
2424
cmp $(SAMPLE_CAT) /tmp/cat_output
2525
./grol_cvm programs/cat.vm < $(SAMPLE_CAT) > /tmp/cat_output
2626
cmp $(SAMPLE_CAT) /tmp/cat_output
27+
echo -n "A" | ./vm run -quiet programs/cat.vm > /tmp/cat_single
28+
echo -n "A" > /tmp/cat_expected
29+
cmp /tmp/cat_expected /tmp/cat_single
30+
echo -n "A" | ./grol_cvm programs/cat.vm > /tmp/cat_single
31+
cmp /tmp/cat_expected /tmp/cat_single
2732

2833
run: vm
2934
./vm compile -loglevel debug programs/simple.asm

asm/asm.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func compile(reader *bufio.Reader, writer *bufio.Writer) int {
215215
if narg == 0 {
216216
return log.FErrf("Expecting at least 1 argument for %s, got none", instr)
217217
}
218-
case "incrr", "incrs", "sys", "syss", "storesb":
218+
case "incrr", "incrs", "sys", "syss", "storesb", "jne", "jeq", "jlt", "jgt", "jgte", "jlte":
219219
if narg != 2 {
220220
return log.FErrf("Expecting 2 arguments for %s, got %d (%v)", instr, narg, args)
221221
}
@@ -351,6 +351,19 @@ func compile(reader *bufio.Reader, writer *bufio.Writer) int {
351351
}
352352
op = op.SetOperand(cpu.ImmediateData(v))
353353
is48bit = true
354+
case cpu.JNE, cpu.JEQ, cpu.JLT, cpu.JGT, cpu.JGTE, cpu.JLTE:
355+
// 2 arguments: value to compare and label for destination
356+
label = args[1]
357+
v, err := parseArg(args[0])
358+
if err != nil {
359+
return log.FErrf("Failed to parse argument %q: %v", args[0], err)
360+
}
361+
if v < 0 || v > 255 {
362+
return log.FErrf("Jump comparison value out of range (0 to 255): %d", v)
363+
}
364+
// Encode as: lower 8 bits = value, upper bits = destination (to be filled in by emitCode)
365+
op = op.SetOperand(cpu.ImmediateData(v))
366+
is48bit = true
354367
default:
355368
// allow labels as arguments even for immediate operands (eg load the address into accumulator)
356369
if isAddressLabel(arg) {

cpu/cpu.go

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -275,38 +275,89 @@ func execute(pc ImmediateData, program []Operation, accumulator int64) (int64, i
275275
if Debug {
276276
log.Debugf("AndI at PC: %d, value: %d -> %d", pc, op.OperandInt64(), accumulator)
277277
}
278-
case JNZ:
279-
if accumulator != 0 {
278+
case JNE:
279+
param := op.OperandInt64()
280+
addr := param >> 8
281+
value := param & 0xFF
282+
if accumulator != value {
280283
if Debug {
281-
log.Debugf("JNZ at PC: %d, jumping to PC: +%d", pc, op.OperandInt64())
284+
log.Debugf("JNE at PC: %d, jumping to PC: +%d", pc, addr)
282285
}
283-
pc += op.Operand()
286+
pc += ImmediateData(addr)
284287
continue
285288
}
286289
if Debug {
287-
log.Debugf("JNZ at PC: %d, not jumping", pc)
290+
log.Debugf("JNE at PC: %d, not jumping", pc)
288291
}
289-
case JNEG:
290-
if accumulator < 0 {
292+
case JEQ:
293+
param := op.OperandInt64()
294+
addr := param >> 8
295+
value := param & 0xFF
296+
if accumulator == value {
291297
if Debug {
292-
log.Debugf("JNEG at PC: %d, jumping to PC: +%d", pc, op.OperandInt64())
298+
log.Debugf("JEQ at PC: %d, jumping to PC: +%d", pc, addr)
293299
}
294-
pc += op.Operand()
300+
pc += ImmediateData(addr)
295301
continue
296302
}
297303
if Debug {
298-
log.Debugf("JNEG at PC: %d, not jumping", pc)
304+
log.Debugf("JEQ at PC: %d, not jumping", pc)
299305
}
300-
case JPOS:
301-
if accumulator >= 0 {
306+
case JLT:
307+
param := op.OperandInt64()
308+
addr := param >> 8
309+
value := param & 0xFF
310+
if accumulator < value {
302311
if Debug {
303-
log.Debugf("JPOS at PC: %d, jumping to PC: +%d", pc, op.OperandInt64())
312+
log.Debugf("JLT at PC: %d, jumping to PC: +%d", pc, addr)
304313
}
305-
pc += op.Operand()
314+
pc += ImmediateData(addr)
306315
continue
307316
}
308317
if Debug {
309-
log.Debugf("JPOS at PC: %d, not jumping", pc)
318+
log.Debugf("JLT at PC: %d, not jumping", pc)
319+
}
320+
case JGT:
321+
param := op.OperandInt64()
322+
addr := param >> 8
323+
value := param & 0xFF
324+
if accumulator > value {
325+
if Debug {
326+
log.Debugf("JGT at PC: %d, jumping to PC: +%d", pc, addr)
327+
}
328+
pc += ImmediateData(addr)
329+
continue
330+
}
331+
if Debug {
332+
log.Debugf("JGT at PC: %d, not jumping", pc)
333+
}
334+
case JGTE:
335+
param := op.OperandInt64()
336+
addr := param >> 8
337+
value := param & 0xFF
338+
if accumulator >= value {
339+
if Debug {
340+
log.Debugf("JGTE at PC: %d, jumping to PC: +%d", pc, addr)
341+
}
342+
pc += ImmediateData(addr)
343+
continue
344+
}
345+
if Debug {
346+
log.Debugf("JGTE at PC: %d, not jumping", pc)
347+
}
348+
case JLTE:
349+
param := op.OperandInt64()
350+
addr := param >> 8
351+
value := param & 0xFF
352+
if accumulator <= value {
353+
if Debug {
354+
log.Debugf("JLTE at PC: %d, jumping to PC: +%d", pc, addr)
355+
}
356+
pc += ImmediateData(addr)
357+
continue
358+
}
359+
if Debug {
360+
log.Debugf("JLTE at PC: %d, not jumping", pc)
310361
}
311362
case JumpR:
312363
if Debug {

cpu/cpu_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,18 @@ func TestOperandWithOpcode(t *testing.T) {
124124
}
125125

126126
// Set a different opcode, operand should remain
127-
op = op.SetOpcode(JNZ)
128-
if op.Opcode() != JNZ {
129-
t.Errorf("Opcode() = %v, want %v", op.Opcode(), JNZ)
127+
op = op.SetOpcode(JNE)
128+
if op.Opcode() != JNE {
129+
t.Errorf("Opcode() = %v, want %v", op.Opcode(), JNE)
130130
}
131131
if op.Operand() != 42 {
132132
t.Errorf("Operand() = %d, want 42", op.Operand())
133133
}
134134

135135
// Set a different operand, opcode should remain
136136
op = op.SetOperand(-100)
137-
if op.Opcode() != JNZ {
138-
t.Errorf("Opcode() = %v, want %v", op.Opcode(), JNZ)
137+
if op.Opcode() != JNE {
138+
t.Errorf("Opcode() = %v, want %v", op.Opcode(), JNE)
139139
}
140140
if op.Operand() != -100 {
141141
t.Errorf("Operand() = %d, want -100", op.Operand())

cpu/instruction.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ const (
1515
ModI // A = A % param
1616
ShiftI // A = A << param
1717
AndI // A = A & param
18-
JNZ // Jump if A != 0
19-
JNEG // Jump if A < 0
20-
JPOS // Jump if A >= 0
18+
JNE // Jump if A != param
19+
JEQ // Jump if A == param
20+
JLT // Jump if A < param
21+
JGT // Jump if A > param
22+
JGTE // Jump if A >= param
23+
JLTE // Jump if A <= param
2124
JumpR // Unconditional jump to relative address
2225
LoadR // Load from relative address (A = *[PC + param])
2326
AddR // A = A + *[PC + param]

cpu/instruction_string.go

Lines changed: 32 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cvm/cvm.c

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -135,27 +135,60 @@ void run_program(CPU *cpu) {
135135
DEBUG_PRINT("AndI %" PRId64 " at PC %" PRId64 "\n", operand, cpu->pc);
136136
cpu->accumulator &= operand;
137137
break;
138-
case JNZ:
139-
DEBUG_PRINT("JNZ %" PRId64 " at PC %" PRId64 "\n", operand, cpu->pc);
140-
if (cpu->accumulator != 0) {
141-
cpu->pc += operand;
138+
case JNE: {
139+
int64_t addr = operand >> 8;
140+
int64_t value = operand & 0xFF;
141+
DEBUG_PRINT("JNE at PC %" PRId64 ", addr: %" PRId64 ", value: %" PRId64 "\n", cpu->pc, addr, value);
142+
if (cpu->accumulator != value) {
143+
cpu->pc += addr;
142144
continue;
143145
}
144-
break;
145-
case JNEG:
146-
DEBUG_PRINT("JNEG %" PRId64 " at PC %" PRId64 "\n", operand, cpu->pc);
147-
if (cpu->accumulator < 0) {
148-
cpu->pc += operand;
146+
} break;
147+
case JEQ: {
148+
int64_t addr = operand >> 8;
149+
int64_t value = operand & 0xFF;
150+
DEBUG_PRINT("JEQ at PC %" PRId64 ", addr: %" PRId64 ", value: %" PRId64 "\n", cpu->pc, addr, value);
151+
if (cpu->accumulator == value) {
152+
cpu->pc += addr;
149153
continue;
150154
}
151-
break;
152-
case JPOS:
153-
DEBUG_PRINT("JPOS %" PRId64 " at PC %" PRId64 "\n", operand, cpu->pc);
154-
if (cpu->accumulator >= 0) {
155-
cpu->pc += operand;
155+
} break;
156+
case JLT: {
157+
int64_t addr = operand >> 8;
158+
int64_t value = operand & 0xFF;
159+
DEBUG_PRINT("JLT at PC %" PRId64 ", addr: %" PRId64 ", value: %" PRId64 "\n", cpu->pc, addr, value);
160+
if (cpu->accumulator < value) {
161+
cpu->pc += addr;
156162
continue;
157163
}
158-
break;
164+
} break;
165+
case JGT: {
166+
int64_t addr = operand >> 8;
167+
int64_t value = operand & 0xFF;
168+
DEBUG_PRINT("JGT at PC %" PRId64 ", addr: %" PRId64 ", value: %" PRId64 "\n", cpu->pc, addr, value);
169+
if (cpu->accumulator > value) {
170+
cpu->pc += addr;
171+
continue;
172+
}
173+
} break;
174+
case JGTE: {
175+
int64_t addr = operand >> 8;
176+
int64_t value = operand & 0xFF;
177+
DEBUG_PRINT("JGTE at PC %" PRId64 ", addr: %" PRId64 ", value: %" PRId64 "\n", cpu->pc, addr, value);
178+
if (cpu->accumulator >= value) {
179+
cpu->pc += addr;
180+
continue;
181+
}
182+
} break;
183+
case JLTE: {
184+
int64_t addr = operand >> 8;
185+
int64_t value = operand & 0xFF;
186+
DEBUG_PRINT("JLTE at PC %" PRId64 ", addr: %" PRId64 ", value: %" PRId64 "\n", cpu->pc, addr, value);
187+
if (cpu->accumulator <= value) {
188+
cpu->pc += addr;
189+
continue;
190+
}
191+
} break;
159192
case JumpR:
160193
DEBUG_PRINT("JumpR %" PRId64 " at PC %" PRId64 "\n", operand, cpu->pc);
161194
cpu->pc += operand;

cvm/cvm.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ enum Instruction {
1010
ModI,
1111
ShiftI,
1212
AndI,
13-
JNZ,
14-
JNEG,
15-
JPOS,
13+
JNE,
14+
JEQ,
15+
JLT,
16+
JGT,
17+
JGTE,
18+
JLTE,
1619
JumpR,
1720
LoadR,
1821
AddR,

programs/cat.asm

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44
read:
55
LoadI 32 ; read up to 32 bytes at a time
66
Sys Read buf
7-
SubI 1 ; so both 0 and -1 skip the write
8-
JPOS write
9-
AddI 1 ; back to 0 vs -1
10-
JNEG error
11-
; normal EOF case, no error:
7+
JGT 0 write ; proceed to write if any bytes were read
8+
JLT 0 error ; jump if error
9+
; Last case 0 read == normal EOF case, no error:
1210
Sys Exit 0
1311
write:
1412
Sys Write buf
15-
JPOS read
13+
JGT 0 read
1614
; write error
1715
error:
1816
Sys Exit 1

0 commit comments

Comments
 (0)