目的
昨日、NECのV30で8080の実験をする環境を整えました。
z80アセンブラで生成した機械語をV30実機上で実行
しかし今の方法では8080モードから8086モードへ戻って画面表示をして止めています。
今回は8080側から画面表示をする時にだけ8086モードへ遷移し、必要な処理をしてから又8080モードへ戻るように変更します。
8080側でCALLN命令を実行すると、IVTに実行した8086の処理へ飛べます。
8086側でiretを実行すると又8080側へ戻れます。
実装
nasm -f bin 8086.asm -o 8086.bin
z80asm -o 8080.bin 8080.asm
cat 8086.bin 8080.bin > test.bin
lsblk
sudo dd if=test.bin of=/dev/sdb bs=512 count=3 conv=notrunc
8086.asm
org 0x7C00
start:
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
; ディスクから第2(8086モード作業場),3(8080側)セクタを 0x7E00 に読み込む
mov ah, 0x02 ; INT 13h 2: 読み込み
mov al, 2 ; 読み込むセクタ数 = 1
mov ch, 0 ; シリンダ = 0
mov cl, 2 ; セクタ番号 = 2(1始まり)
mov dh, 0 ; ヘッド = 0
mov dl, 0x80 ; ドライブ番号
mov bx, 0x7E00 ; 読み込み先アドレス
int 0x13
jc disk_error ; エラー時に無限ループ
; 読み込んだコードへ跳ぶ(第2セクタ)
jmp 0x0000:0x7E00
disk_error:
jmp $
times 510-($-$$) db 0
dw 0xAA55
; 8080コード入口
%define TARGET_VECC 0x80
%define TARGET_ADDR (TARGET_VECC * 4)
%define IVT_40 (0x40 * 4) ; 0x0100
BUFFER_ADDR equ 0x6000 ; 8080モード用の文字バッファ
start2:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
; --- IVT 0x80 に 8080コードの開始地点を登録 ---
mov word [TARGET_ADDR], 0x8000 ; オフセット
mov word [TARGET_ADDR + 2], 0 ; セグメント(CS)
; IVT 0x40 に CS=0, IP=print_addr を登録
print_addr equ (print - start2) + 0x7E00
mov word [IVT_40], print_addr ; IP
mov word [IVT_40 + 2], 0 ; CS
call init_8080buffer
; 8080モードへ移行
db 0x0F, 0xFF, TARGET_VECC
hlt_loop:
hlt
jmp hlt_loop
print:
xor ax, ax
mov ds, ax
mov ax, 0xB800
mov es, ax
call copy_8080buffer_to_vram ; バッファからVRAMに複製
iret
;-----------------------
; 8080用画面バッファからVRAMへ複製
;-----------------------
copy_8080buffer_to_vram:
push ax
push cx
push si
push di
push ds
push es
xor ax, ax
mov ds, ax
mov si, BUFFER_ADDR
mov ax, 0B800h
mov es, ax
xor di, di
mov cx, 4000 ; 80*25*2
rep movsb ; DS:SI → ES:DI
pop es
pop ds
pop di
pop si
pop cx
pop ax
ret
;-----------------------
; 8080画面出力用BUFFER初期化
;-----------------------
init_8080buffer:
push ax
push cx
push es
push di
; ES=0x0000 DI=0x6000
xor ax, ax
mov es, ax
mov di, BUFFER_ADDR
mov cx, 80*25
mov ax, 0x0720 ; AH=属性, AL=' '
cld
rep stosw ; ES:[DI] ← AX , DI ← DI + 2
pop di
pop es
pop cx
pop ax
ret
times 512-($-start2) db 0
8080.asm
org 0x8000
ld a, 0
ld b, 9 ; 9回ループ
sum_loop:
add a, b
dec b
jp nz, sum_loop
; ここでAに合計が入っている (45)
; ASCII 55=- よって-が表示される
ld (0x6000), a
ld a, 0x4f
ld (0x6001), a
; CALLN 40h → IVT 0x40 の 8086 print を呼ぶ
db 0xED, 0xED, 0x40 ; calln 0x40
;db 0xed,0xfd;
ds 512 - ($ - 0x8000)