MZ:: .signature dw "MZ" .bytes_in_last_page dw .LENGTH and 1FFh .number_of_pages dw (.LENGTH-1) shr 9 + 1 .number_of_relocations dw .NUMBER_OF_RELOCATIONS .number_of_header_paragraphs dw .HEADER_LENGTH shr 4 .minimum_heap dw (.LENGTH+.RESERVED_LENGTH-1) shr 4 - (.LENGTH-1) shr 4 .maximum_heap dw 0FFFFh .initial_ss dw 0 .initial_sp dw 0 .checksum dw 0 .initial_ip dw 0 .initial_cs dw 0 .relocations_offset dw .relocations .overlay_number dw 0 .relocations dw .NUMBER_OF_RELOCATIONS dup (?,?) rb 0Fh - ($%+0Fh) and 0Fh .HEADER_LENGTH = $ .RELOCATION_INDEX = 0 .ENTRY_DEFINED = 0 .HEAP_DEFINED = 0 .STACK_DEFINED = 0 .STACK_LENGTH = 1000h org 0 macro entry? definition local v if MZ.ENTRY_DEFINED err 'setting already specified' else match seg:offs, definition v = seg if v relativeto MZ.segment store v - MZ.segment : word at MZ : MZ.initial_cs else err 'incorrect segment' end if v = offs if v >= 0 & v < 10000h store v : word at MZ : MZ.initial_ip else err 'value out of range' end if MZ.ENTRY_DEFINED = 1 else err 'invalid argument' end match end macro macro heap? definition local v,min if MZ.HEAP_DEFINED err 'setting already specified' else v = definition if v >= 0 & v < 10000h load min : word from MZ : MZ.minimum_heap v = v + min if v > 0FFFFh v = 0FFFFh end if store v : word at MZ : MZ.maximum_heap else err 'value out of range' end if MZ.HEAP_DEFINED = 1 end if end macro macro stack? definition local v if MZ.STACK_DEFINED err 'setting already specified' else match seg:offs, definition v = seg if v relativeto MZ.segment store v - MZ.segment : word at MZ : MZ.initial_ss else err 'incorrect segment' end if v = offs if v >= 0 & v < 10000h store v : word at MZ : MZ.initial_sp else err 'value out of range' end if MZ.STACK_DEFINED = 1 MZ.STACK_LENGTH = 0 else MZ.STACK_DEFINED = 1 MZ.STACK_LENGTH = definition end match end macro element MZ.segment macro segment? definition rb 0Fh - ($%+0Fh) and 0Fh match name =use16?, definition name := MZ.segment + ($%-MZ.HEADER_LENGTH) shr 4 use16 else match name =use32?, definition name := MZ.segment + ($%-MZ.HEADER_LENGTH) shr 4 use32 else match name, definition name := MZ.segment + ($%-MZ.HEADER_LENGTH) shr 4 end match org 0 end macro calminstruction calminstruction?.initsym? var*, val& publish var, val end calminstruction calminstruction calminstruction?.asm? line& local name, i initsym name, name.0 match name.i, name compute i, i+1 arrange name, name.i publish name, line arrange line, =assemble name assemble line end calminstruction iterate , dw,word, dd,dword calminstruction word? value compute value, value check value relativeto MZ.segment jno plain local offset compute offset, $% emit word, value - MZ.segment check $% > offset jno done compute offset, offset - MZ.HEADER_LENGTH compute offset, offset and 0FFFFh + (offset and not 0FFFFh) shl 12 asm store offset:4 at MZ : MZ.relocations + MZ.RELOCATION_INDEX shl 2 compute MZ.RELOCATION_INDEX, MZ.RELOCATION_INDEX + 1 done: exit plain: emit word, value end calminstruction calminstruction dw? definitions& local value, n start: match value=,definitions, definitions, () jyes recognize match value, definitions arrange definitions, recognize: match n =dup? value, value, () jyes duplicate match ?, value jyes reserve call word, value next: match , definitions jno start take , definitions take definitions, definitions jyes next exit reserve: emit word jump next duplicate: match (value), value stack: check n jno next take definitions, value arrange value, definitions compute n, n - 1 jump stack end calminstruction calminstruction (label) dw? definitions& local cmd arrange cmd, =label label : =word assemble cmd arrange cmd, =dw definitions assemble cmd end calminstruction end iterate calminstruction align? boundary,value:? compute boundary, (boundary-1)-((0 scaleof $)+boundary-1) mod boundary arrange value, =db boundary =dup value assemble value end calminstruction postpone if MZ.STACK_LENGTH rb 0Fh - ($%+0Fh) and 0Fh store ($%-MZ.HEADER_LENGTH) shr 4 : word at MZ : MZ.initial_ss rb MZ.STACK_LENGTH store MZ.STACK_LENGTH : word at MZ : MZ.initial_sp end if MZ.LENGTH = $%% MZ.RESERVED_LENGTH = $%-$%% MZ.NUMBER_OF_RELOCATIONS = MZ.RELOCATION_INDEX end postpone