# Generating code for the 8086 CPU --- ## Summary - [A simple program](#a-simple-program) - [Interaction with labels](#interaction-with-labels) - [Calling the BIOS](#calling-the-bios) ## A simple program The `x86_8086` package is based on the `arch` package. Every registers and more than 81 instructions are supported. Instead of generating raw Assembly code, we can use the abstractions provided by this package. Here is an example: ```py program.arch.instructions.mov(program.arch.registers.AX, 0x28) ``` This is like ```py program.generate_line("mov ax, 0x28") ``` But you could find that the line above is too verbose. Fortunately, the `Program` class provides a shortcut named `asm` for `arch.instructions` and `regs` for `arch.registers`. ```py program.asm.mov(program.regs.AX, 0x28) ``` This line is smaller and more readable. Let's add a few instructions: ```py program.asm.mov(program.regs.AX, 0x28) program.asm.mov(program.regs.BX, program.regs.AX) program.asm.add(program.regs.AX, program.regs.BX) ``` If you generate the code, you will get the following result: ```asm mov ax, 40 mov bx, ax add ax, bx ``` ## Interaction with labels The 8086 instruction wrappers work well with labels. For example, let's define a label and jump to it. ```py @label() def example(): pass prog.asm.jmp("example") ``` Conditionnal jumps and comparisons are supported too. You can run this example and read the generated code: ```py from libpyosdev.program import Program from libpyosdev.label import label from libpyosdev.x86_8086.infos import info8086 class Labels8086(Program): def __init__(self): super().__init__("8086_labels", info8086) @label() def start(self): self.asm.mov(self.regs.AX, 2) self.asm.add(self.regs.AX, 4) self.asm.jmp("loop") @label() def loop(self): self.asm.inc(self.regs.AX) self.asm.cmp(self.regs.AX, 10) self.asm.jne("loop") def _1_body(self): self.start() self.loop() def run(self): self.write() prog = Labels8086() prog.run() ``` You will get the following output: ```asm start: mov ax, 2 add ax, 4 jmp loop loop: inc ax cmp ax, 10 jne loop ``` ## Calling the BIOS The Intel x86 8086 is an architecture that supports the BIOS, so you can call its wrappers thanks to LibPyOSDev. In the example below, we call an interrupt to write a character to the screen and move the cursor. Without the BIOS class, you would write this: ```py prog.asm.mov(prog.regs.AH, 0x0E) prog.asm.mov(prog.regs.AL, ord('A')) prog.asm.mov(prog.regs.BH, 0) # page number, optionnal prog.asm.mov(progs.regs.BL, 0x0F) prog.asm.int_(0x10) ``` But with the BIOS class, you can do this in one line: ```py prog.arch.bios.interrupt(prog.arch.bios.TELETYPE_PUTCHAR, ord('A'), 0, 0x0F) # page number is required here ``` And you can make it even shorter: ```py prog.bios.interrupt(prog.bios.TELETYPE_PUTCHAR, ord('A'), 0, 0x0F) ``` The only thing you need to be careful about is passing values to registers. For `TELETYPE_PUTCHAR`, the right order is AL, BH, BL.