More opcodes and usage info
CloseOmf(f);
end;
+procedure PrintUsage;
+begin
+ Writeln('Usage: asm89 <input.asm> [output.obj]');
+ Writeln('');
+ Writeln('The output object file is optional. If it is not specified, the output file');
+ Writeln('Is the input file with the .obj extension');
+end;
+
+procedure FatalError(const message: string; const print_usage: boolean);
+begin
+ Writeln(message);
+ Writeln('');
+ if print_usage then PrintUsage;
+ Halt(1);
+end;
+
begin
Writeln('asm89 compiler v', VERSION);
Writeln('');
- if ParamCount < 1 then begin
- Writeln('You must specify an input file');
- Halt(1);
- end;
+ if ParamCount < 1 then
+ FatalError('You must specify an input file', true);
infile := ParamStr(1);
if ParamCount < 2 then begin
outfile := ChangeExtension(ParamStr(1), 'obj');
_ScreenFuzz:
lpd ga, [pp].4 ; pp.4 is the input buffer address
movi ix, 0
-1: inc [ga+ix+]
+loop: inc [ga+ix+]
andi ix, 07ffh
- jmp 1-
-
+ jmp loop
Inc(rec.head.length);
rec.data[rec.head.length] := cclass;
Inc(rec.head.length);
- for i := 0 to comment_len do begin
+ for i := 1 to comment_len do begin
rec.data[rec.head.length] := Byte(comment[i]);
Inc(rec.head.length);
end;
end;
InstructionRBP = (
- rbpReg, { RbP Encodes a register }
- rbpBit, { RbP Encodes a bit position }
- rbpPtrReg, { RbP encodes a pointer register }
+ rbpReg, { RbP Encodes a register (rrr) }
+ rbpBit, { RbP Encodes a bit position (bbb) }
+ rbpPtrReg, { RbP encodes a pointer register (PPP) }
rbpNone, { RbP encodes nothing (0b000) }
rbpHlt, { RbP encodes 0b001 }
rbpSintr, { RbP encodes 0b010 }
rbpJmp { RbP encodes 0b100 }
);
InstructionWidth = (widByte, widWord);
+{ | low order byte | high order byte | }
+{ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | }
+{ | r/b/P | W B | A A | W | OPCODE | MM | }
+{ }
+{ r/b/P = Register, Bit, or Pointer/Register Select }
+{ RRR bbb PPP }
+{ 000 - GA 000 - bit 0 000 - GA }
+{ 001 - GB 001 - bit 1 001 - GB }
+{ 010 - GC 010 - bit 2 010 - GC }
+{ 011 - GA 011 - bit 3 100 - TP }
+{ 100 - GA 100 - bit 4 }
+{ 101 - GA 101 - bit 5 }
+{ 110 - GA 110 - bit 6 }
+{ 111 - GA 111 - bit 7 }
+{ }
+{ WB = Number of immediate/displacement value bytes (EncWB) }
+{ 00 - Reserved (wReserved) }
+{ 01 - 1 byte (wOne) }
+{ 10 - 2 bytes (word) (wTwo) }
+{ 11 - TSL instruction only (wTSL) }
+{ }
+{ AA = Memory Address Mode }
+{ 00 - Base address only }
+{ 01 - Base address + 8 bit offset }
+{ 10 - Base address + index register }
+{ 11 - Base address + index register, post-increment }
+{ }
+{ W = Memory Data Width }
+{ 0 - 1 byte (widByte) }
+{ 1 - 2 bytes (widWord) }
+{ }
+{ OPCODE = Opcode, see below }
+{ }
+{ MM = Base Memory Address Select }
+{ 00 - GA }
+{ 01 - GB }
+{ 10 - GC }
+{ 11 - PP }
InstructionEncoding = record
{ these parts are matched against }
m: Mnemonic;
o2: OperandType;
o3: OperandType;
{ these parts are encoded when the above fields match }
- op: Byte;
+ op: Byte; { pre-shifted into the high 6-bits }
w: InstructionWidth;
wb: EncWB;
rbp: InstructionRBP;
end;
-const IEnc: array[0..18] of InstructionEncoding = (
+const IEnc: array[0..29] of InstructionEncoding = (
(m: mADD; o1: OpRegister; o2: OpMemory; o3: OpAbsent;
op: $A0; w: widWord; wb: wReserved; rbp: rbpReg),
(m: mANDBI; o1: OpMemory; o2: OpImmediate; o3: OpAbsent;
op: $C8; w: widByte; wb: wOne; rbp: rbpNone),
+ (m: mANDI; o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
+ op: $28; w: widWord; wb: wTwo; rbp: rbpReg),
+
+ (m: mANDI; o1: OpMemory; o2: OpImmediate; o3: OpAbsent;
+ op: $C8; w: widWord; wb: wTwo; rbp: rbpNone),
+
(m: mCALL; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
op: $9C; w: widWord; wb: wLocation; rbp: rbpJmp),
+ (m: mCLR; o1: OpMemory; o2: OpBit; o3: OpAbsent;
+ op: $F8; w: widByte; wb: wReserved; rbp: rbpBit),
+
+ (m: mDEC; o1: OpRegister; o2: OpAbsent; o3: OpAbsent;
+ op: $3C; w: widByte; wb: wReserved; rbp: rbpReg),
+
+ (m: mDEC; o1: OpMemory; o2: OpAbsent; o3: OpAbsent;
+ op: $EC; w: widWord; wb: wReserved; rbp: rbpNone),
+
+ (m: mDECB; o1: OpMemory; o2: OpAbsent; o3: OpAbsent;
+ op: $EC; w: widByte; wb: wReserved; rbp: rbpNone),
+
(m: mHLT; o1: OpAbsent; o2: OpAbsent; o3: OpAbsent;
op: $48; w: widByte; wb: wReserved; rbp: rbpHlt),
+ (m: mINC; o1: OpRegister; o2: OpAbsent; o3: OpAbsent;
+ op: $38; w: widByte; wb: wReserved; rbp: rbpReg),
+
+ (m: mINC; o1: OpMemory; o2: OpAbsent; o3: OpAbsent;
+ op: $E8; w: widWord; wb: wReserved; rbp: rbpNone),
+
(m: mJBT; o1: OpMemory; o2: OpBit; o3: OpLocation;
op: $BC; w: widByte; wb: wLocation; rbp: rbpBit),
+ (m: mJMCE; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $B0; w: widByte; wb: wLocation; rbp: rbpNone),
+
+ (m: mJMCNE; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $B4; w: widByte; wb: wLocation; rbp: rbpNone),
+
(m: mJMP; o1: OpLocation; o2: OpAbsent; o3: OpAbsent;
- op: $20; w: widWord; wb: wTwo; rbp: rbpJmp),
+ op: $20; w: widWord; wb: wLocation; rbp: rbpJmp), { AUG shows w changing for 8/16-bit displacement }
+
+ (m: mJNBT; o1: OpMemory; o2: OpBit; o3: OpLocation;
+ op: $B8; w: widByte; wb: wLocation; rbp: rbpBit),
+
+ (m: mJNZ; o1: OpRegister; o2: OpLocation; o3: OpAbsent;
+ op: $40; w: widByte; wb: wLocation; rbp: rbpReg),
+
+ (m: mJNZ; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E0; w: widWord; wb: wLocation; rbp: rbpNone),
+
+ (m: mJNZB; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E0; w: widByte; wb: wLocation; rbp: rbpNone),
+
+ (m: mJZ; o1: OpRegister; o2: OpLocation; o3: OpAbsent;
+ op: $44; w: widByte; wb: wLocation; rbp: rbpReg),
+
+ (m: mJZ; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E4; w: widWord; wb: wLocation; rbp: rbpNone),
+
+ (m: mJZB; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E4; w: widByte; wb: wLocation; rbp: rbpNone),
+
+ (m: mLCALL; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $9C; w: widWord; wb: wTwo; rbp: rbpJmp),
+
+ (m: mLJBT; o1: OpMemory; o2: OpBit; o3: OpLocation;
+ op: $BC; w: widByte; wb: wTwo; rbp: rbpBit),
+
+ (m: mLJMCE; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $B0; w: widByte; wb: wTwo; rbp: rbpNone),
+
+ (m: mLJMCNE; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $B4; w: widByte; wb: wTwo; rbp: rbpNone),
+
+ (m: mLJMP; o1: OpLocation; o2: OpAbsent; o3: OpAbsent;
+ op: $20; w: widWord; wb: wTwo; rbp: rbpJmp), { AUG shows w changing for 8/16-bit displacement }
+
+ (m: mLJNBT; o1: OpMemory; o2: OpBit; o3: OpLocation;
+ op: $B8; w: widByte; wb: wTwo; rbp: rbpBit),
+
+ (m: mLJNZ; o1: OpRegister; o2: OpLocation; o3: OpAbsent;
+ op: $40; w: widByte; wb: wTwo; rbp: rbpReg),
+
+ (m: mLJNZ; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E0; w: widWord; wb: wTwo; rbp: rbpNone),
+
+ (m: mLJNZB; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E0; w: widByte; wb: wTwo; rbp: rbpNone),
+
+ (m: mLJZ; o1: OpRegister; o2: OpLocation; o3: OpAbsent;
+ op: $44; w: widByte; wb: wTwo; rbp: rbpReg),
+
+ (m: mLJZ; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E4; w: widWord; wb: wTwo; rbp: rbpNone),
+
+ (m: mLJZB; o1: OpMemory; o2: OpLocation; o3: OpAbsent;
+ op: $E4; w: widByte; wb: wTwo; rbp: rbpNone),
+
+ (m: mLPD; o1: OpPointer; o2: OpMemory; o3: OpAbsent;
+ op: $88; w: widWord; wb: wReserved; rbp: rbpPtrReg),
+
+ (m: mLPDI; o1: OpPointer; o2: OpImmediate; o3: OpAbsent;
+ op: $08; w: widWord; wb: wTwo; rbp: rbpPtrReg),
+
+ (m: mMOV; o1: OpMemory; o2: OpRegister; o3: OpAbsent;
+ op: $84; w: widWord; wb: wReserved; rbp: rbpReg),
+
+ (m: mMOV; o1: OpRegister; o2: OpMemory; o3: OpAbsent;
+ op: $80; w: widWord; wb: wReserved; rbp: rbpReg),
+
+ (m: mMOV; o1: OpMemory; o2: OpMemory; o3: OpAbsent;
+ op: $90; w: widWord; wb: wReserved; rbp: rbpNone),
+ { MOV M, M is encoded as a pair of instructions. Each one encodes a memory
+ register and optional offset. The second opcode is $CC. }
+
+ (m: mMOVB; o1: OpMemory; o2: OpRegister; o3: OpAbsent;
+ op: $84; w: widByte; wb: wReserved; rbp: rbpReg),
+
+ (m: mMOVB; o1: OpRegister; o2: OpMemory; o3: OpAbsent;
+ op: $80; w: widByte; wb: wReserved; rbp: rbpReg),
+
+ (m: mMOVB; o1: OpMemory; o2: OpMemory; o3: OpAbsent;
+ op: $90; w: widByte; wb: wReserved; rbp: rbpNone),
+ { MOVB M, M works just like MOV with a different W field. }
+
+ (m: mMOVI; o1: OpRegister; o2: OpImmediate; o3: OpAbsent;
+ op: $30; w: widWord; wb: wTwo; rbp: rbpReg),
+
+ (m: MMOVI; o1: OpMemory; o2: OpImmediate; o3: OpAbsent;
+ op: $4C; w: widWord; wb: wTwo; rbp: rbpNone),
- (m: mSINTR; o1: OpAbsent; o2: OpAbsent; o3: OpAbsent;
+ (m: mSINTR; o1: OpAbsent; o2: OpAbsent; o3: OpAbsent;
op: $00; w: widByte; wb: wReserved; rbp: rbpSintr)
);
ParseIntLiteral := Word(j);
end;
+function ParseNumericExpression(const s: String; var i: Word): Boolean;
+begin
+ { TODO: actually parse expressions }
+ i := ParseIntLiteral(s);
+ ParseNumericExpression := true;
+end;
+
function ParseMnemonic(const m: String): Mnemonic;
var i: Mnemonic;
begin
l: String;
begin
i := 1;
+ { First try an identifier }
l := ToUpCase(ConsumeIdentifier(a, i));
if i < Length(a) + 1 then begin
Writeln('Malformed location? `', a, '`');
Halt(1);
end;
- if NOT FindSymbol(l, o.loc) then begin
- Writeln('Symbol not found: ', l);
- Halt(1);
+ if FindSymbol(l, o.loc) then begin
+ o.Kind := OpLocation;
+ Exit;
end;
- o.Kind := OpLocation;
+ { Then maybe it's a numeric expression }
+ if ParseNumericExpression(a, o.loc) then
+ o.Kind := OpLocation;
end;
procedure ParseMemory(a: String; var o: Operand);
else if a[i] = '+' then begin
Inc(i);
ConsumeWhitespace(a, i);
- reg := ConsumeRegister(a, i);
+ reg := ToUpCase(ConsumeRegister(a, i));
if reg <> 'IX' then
Exit;
ConsumeWhitespace(a, i);