Skip to content

Instantly share code, notes, and snippets.

@ziggythehamster
Created June 11, 2024 05:53
Show Gist options
  • Save ziggythehamster/0d07b087240da8b745dafcd0a019fc5a to your computer and use it in GitHub Desktop.
Save ziggythehamster/0d07b087240da8b745dafcd0a019fc5a to your computer and use it in GitHub Desktop.
TERA8M proof of concept

I am building this functionality into WD76UTIL but wanted to at least get my proof of concept test in a gist in case it is helpful to one of the other half dozen people with a Teradrive.

BTW, the mod for the Teradrive is to connect A10 on the SIMM sockets (pin 19) to RA10 (pin 126) on the WD76C10. On my model 3 unit, RA10 is accessible through a via.

You cannot connect A11 on the SIMM sockets and you cannot use >4MByte SIMMs, because the chipset doesn't support it.

You must install the SIMMs in pairs.

The SIMMs should be of a Mac/Amiga type - ordinary PC-style 30 pin SIMMs use the A10 and A11 pins as sense pins, and don't wire them up to the memory. This seems to be a backport of the 72 pin SIMM sense standard, because most boards that took 30 pin SIMMs of this size also took 72 pin SIMMs. If the SIMM has a section in the corner for resistors, there is a great chance it will not work here.

I'm building this with the WD76UTIL CMake stuff, and some hacks to make the assembler recognized. Here are the commands that CMake issues:

C:\WATCOM\binnt64\wcl.exe   -foCMakeFiles\tera8m.dir\setsize.asm.obj -c setsize.asm
C:\WATCOM\binnt64\wcl.exe -zq -d+  -I"C:\WATCOM\h" -w3 -bt=dos -za99 -d2 -d2 -zq -bt=dos -0 -ms -ze -zm -oi -os -s -zp1 -foCMakeFiles\tera8m.dir\tera8m.c.obj -c -cc tera8m.c
C:\WATCOM\binnt64\wlink.exe option quiet name tera8m.com opt map  debug all system com option eliminate file {'CMakeFiles\tera8m.dir\setsize.asm.obj' 'CMakeFiles\tera8m.dir\tera8m.c.obj' }
.8086
.model tiny
inp macro port
mov dx, port
in al, dx
tick3
endm
inpw macro port
mov dx, port
in ax, dx
tick3
endm
movedataw macro src, dest, size
setds src ; DS = source
setes dest ; ES = dest
mov cx, size ; CX = size in words
rep movsw ; copy!
endm
outp macro port, data
mov al, data
mov dx, port
out dx, al
tick3
endm
outpw macro port, data
mov ax, data
mov dx, port
out dx, ax
tick3
endm
setborder macro color
inp 0x3DA ; clear VGA attribute flip-flop
outp 0x3C0, 0x11 ; select VGA register 0x11 (overscan color)
outp 0x3C0, color ; set color
endm
setds macro seg
mov ax, seg ;
mov ds, ax ; set DS to provided segment
xor si, si ; set DS:SI = seg:0000
endm
setes macro seg
mov ax, seg ;
mov es, ax ; set ES to provided segment
xor di, di ; set ES:DI = seg:0000
endm
tick macro
db 0xeb, 0x00 ; jmp to the next instruction, as a delay
endm
tick3 macro
tick
tick
tick
endm
wd76_lock macro
outp 0xf073, 0x00 ; lock registers
endm
wd76_unlock macro
outp 0xf073, 0xda ; unlock registers
endm
.code
;
; setsize - sets the memory size register to whatever is passed in ax
;
public setsize_
setsize_ proc near
mov bx, ax ; we need to stash this for a moment
setborder 0x04 ; red
setds cs
lea si, [setsize_vram] ; the start of the data to copy
setes 0xB800
xor di, di ; set VRAM offset
mov ax, end_setsize_code ;
sub ax, setsize_vram ; set ax to number of bytes to copy
shr ax, 1 ;
mov cx, ax ; setup copy
rep movsw ; perform copy
setborder 0x05 ; magenta
setds 0xB800
mov ax, bx ; put the parameter in ax
jmp 0xB800, 0x0500 ; jump to VRAM, offset by our buffers
hlt ; you shouldn't get here
setsize_vram:
db 0x0400 dup (0x00) ; space for the entire IVT, 1024 bytes
db 0x0100 dup (0x00) ; space for the entire BDA, 256 bytes
setsize_code_start:
mov bx, ax ; ax and cx are used later
setborder 0x01 ; blue
cli ; clear interrupts
setborder 0x38 ; lavender
;
; backup IVT and BDA
;
movedataw 0x0000, 0xB800, 0x0200 ; backup the IVT (0x200 words = 1024 bytes)
movedataw 0x0040, 0xB840, 0x0080 ; backup the BDA (0x80 words = 256 bytes)
setds 0xB800 ; put DS back to this segment
;
; set our new memory size, which jumbles all RAM
; except VRAM
;
wd76_unlock
setborder 0x02 ; green
mov ax, bx ; put the new size back
outpw 0x3872, ax ; write the new memory size
setborder 0x07 ; white
;
; restore IVT and BDA
;
movedataw 0xB800, 0x0000, 0x0200 ; restore the IVT
movedataw 0xB840, 0x0040, 0x0080 ; restore the BDA
setds 0xB800 ; put DS back to this segment
setborder 0x03 ; cyan
;
; disable BIOS shadowing and write protect
;
inpw 0x6072 ; get current value of RAM shadow & WP register
mov cx, ax ; store original register in cx
and ax, 0xECFF ; mask out the shadow write protect and disable shadowing
mov bx, ax ; move to bx so I don't have to write another macro
outpw 0x6072, bx ; disable RAM shadow write protect + shadowing
mov bx, cx ; store original register in bx so we don't overwrite it
setborder 0x09 ; bright blue
wd76_lock
;
; backup the unshadowed BIOS
;
movedataw 0xe000, 0x4000, 0x8000 ; backup VGA BIOS to 0x4000
movedataw 0xf000, 0x5000, 0x8000 ; backup BIOS to 0x5000
setds 0xB800 ; put DS back to this segment
;
; re-enable BIOS shadowing but keep write protect disabled
;
wd76_unlock
and bx, 0xEFFF ;
outpw 0x6072, bx ; mask out write protect but turn shadowing on
wd76_lock
;
; re-shadow the BIOS
;
movedataw 0x4000, 0xe000, 0x8000 ; restore VGA BIOS from 0x4000
movedataw 0x5000, 0xf000, 0x8000 ; restore BIOS from 0x5000
setds 0xB800 ; set DS once again back to this segment
;
; re-enable BIOS shadow write protect
;
setborder 0x0A ; bright green
wd76_unlock
inpw 0x6072 ; get current value of RAM shadow & WP register
or ax, 0x1000 ;
mov bx, ax ;
outpw 0x6072, bx ; turn write protect back on
wd76_lock
;
; set warm boot flag
;
setborder 0x0B ; bright cyan
setes 0x40 ; set ES to BIOS data area
mov ax, 0x72 ;
mov di, ax ; set DI to warm boot flag field of BDA
mov word ptr es:[di], 0x1234 ; set warm boot flag
;
; reset via 8042
; https://wiki.osdev.org/Reboot
;
setborder 0x0D ; bright magenta
empty_kbd_buffer:
inp 0x64 ; read 8042 status
mov bl, al ; we write al with outp
test bl, 0x01 ; check for keyboard data
jz short check_kbd_user_data ; no keyboard data
inp 0x60 ; there was keyboard data, read port
check_kbd_user_data:
test bl, 0x02 ; check for user data
jz short reset ; no more user data, reset this fucker
jmp short empty_kbd_buffer ; another loop
reset:
setborder 0x0F ; bright white
outp 0x64, 0xFE
end_setsize_code:
hlt ; you shouldn't get here
setsize_ endp
end
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <string.h>
#define SPLIT_START_ADDR 0x44 // A23=1, A19=1
#define SPLIT_START_MASK 0xFF00 // high byte needs left alone
#define START_ADDR 0x0040 // A23=1 for bank0, bank1=0
#define BANK1_4M 0x000C // 11 in bit 2+3
#define BANK1_SIZE_MASK 0xFFF3 // bit 2+3 = bank1 size
#define setborder(color) \
_asm { mov ah, 0x0B } \
_asm { mov bh, 0x00 } \
_asm { mov bl, color } \
_asm { int 0x10 }
// EB 00 - jumps over this jump instruction only, and serves as a delay
#define tick() _asm { db 0xeb, 0x00 }
#define tick3() tick(); tick(); tick();
extern void setsize(unsigned int size);
#pragma aux setsize \
parm [ax]
int main(int argc, char* argv[]) {
printf("TERA8M init\n");
unsigned int orig_vga_misc = inp(0x03CC);
printf("VGA RAM enable: %d\n", (orig_vga_misc & 0x02) >> 1);
printf("Determining new register values ...\n");
// unlock registers
outp(0xF073, 0xDA);
unsigned int orig_size = inpw(0x3872);
unsigned int orig_start = inpw(0x4872);
unsigned int orig_split = inpw(0x5872);
unsigned int new_size = (orig_size & BANK1_SIZE_MASK) | BANK1_4M;
unsigned int new_start = START_ADDR;
unsigned int new_split = (orig_split & SPLIT_START_MASK) | SPLIT_START_ADDR;
printf("3872h %04X => %04X\n", orig_size, new_size);
printf("4872h %04X => %04X\n", orig_start, new_start);
printf("5872h %04X => %04X\n", orig_split, new_split);
getch(); // wait for a key
setborder(0x01);
tick3();
outpw(0x5872, new_split);
tick3();
setborder(0x02);
tick3();
outpw(0x4872, new_start);
tick3();
setborder(0x03);
tick3();
// lock registers
outp(0xF073, 0x00);
tick3();
// set size
setsize(new_size);
}
@ziggythehamster
Copy link
Author

Seems like reshadowing the BIOS is required but backing up and restoring the IVT and BDA are not

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment