2

0 ; checksum, to be filled in later
;-------------------
;
-----SUB-
ROUTINE-------------
;-------------------
macro MTT 0,1,2
{
mov eax,0 ; copy register address
mov ebx,1 ; copy register data
mov dx,address ; set port address
out dx,eax ; send address through the port
mov dx,data ; set port data
in eax,dx
and eax,2 ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
}
macro SAVE ; Save all register that will be affected by our code
{
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
}
macro RETURN ; Restore register contents
{
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
}
;
-------------------
;
-------MAIN-
ROUTINE
----------
;-------------------
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
SAVE
;
--------------------
; Patch AM2 Memory Timing
MTT async,async_7,async_data ; Set max async latency to 7ns
;
-------------------—-
RETURN

times (ROM_SIZE_IN_BYTE-$) db 0
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
;-------—CODE
END
-----------
; How to set you memory timing?
; Just type MTT<space>timing name,timing value,timing data
; Exp : async memory to 7.0ns would be -> MTT async,async_7,async_data
; Press F9 to compile it with flat assembler
;
;--------------------
I've have now generated a working PCI Substitute ROM for the ABIT AM2 board NF-M2 nView to set the
Async Latency. I used a version of the above code with the PCI header code that tictac posted in another
thread…
Many Memory Timing Registers and Data are correct, while a few others are as yet to be defined
correctly… The above Code has been revised and commented several times, incorporating updates…
One of the problems I'm running into with writing the AM2 code, is shown in this map of the x88h "DRAM
Timing Low Register". Trp and Trtp are both set with the 3ed hex byte which is fine.
The question is, the 3ed bit of the 3ed byte, is "reserved". Can I change it? Must it stay what it was? Can
it be 0h or 1h? Actually it looks to be "read-only", so it won't change anyhow. Will trying to write to it
cause a problem? I guess I'll have to test it. This situation occurs in about 3-4 registers in the AM2 CPU
and needs to be understood…

The immediate solution is to combine the 2 settings(Trp & Trtp) so the desired combination can be
selected. The "Reserved" bit position in the code is zero(0) for all selections. Here's what it looks like:
code:
; Row Precharge Time/Read Precharge Time Combined
combo1 equ dtl_add ;
combo1_data equ 0FFFFF0FFh ; Trp / Trtp (4bit)
combo1_1 equ 000000000h ; 3 clock / 2/4 clock
combo1_2 equ 000000100h ; 4 clock / 2/4 clock
combo1_3 equ 000000200h ; 5 clock / 2/4 clock
combo1_4 equ 000000300h ; 6 clock / 2/4 clock
combo1_5 equ 000000800h ; 3 clock / 3/5 clock
combo1_6 equ 000000900h ; 4 clock / 3/5 clock
combo1_7 equ 000000A00h ; 5 clock / 3/5 clock
combo1_8 equ 000000B00h ; 6 clock / 3/5 clock
The next combo "problem" is Twr and Trrd both being set by the 6th byte:

Again, the immediate solution is to combine them in the option chart:
code:
; Write Recovery Time/RAS to RAS Delay Combined
combo2 equ dtl_add ;
combo2_data equ 0FF0FFFFFh ; Twr / Trrd (4bit)
combo2_1 equ 000000000h ; 3 clock / 2 clock
combo2_2 equ 000100000h ; 4 clock / 2 clock
combo2_3 equ 000200000h ; 5 clock / 2 clock
combo2_4 equ 000300000h ; 6 clock / 2 clock
combo2_5 equ 000400000h ; 3 clock / 3 clock
combo2_6 equ 000500000h ; 4 clock / 3 clock
combo2_7 equ 000600000h ; 5 clock / 3 clock
combo2_8 equ 000700000h ; 6 clock / 3 clock
combo2_9 equ 000800000h ; 3 clock / 4 clock
combo2_10 equ 000900000h ; 4 clock / 4 clock
combo2_11 equ 000A00000h ; 5 clock / 4 clock
combo2_12 equ 000B00000h ; 6 clock / 4 clock
combo2_13 equ 000C00000h ; 3 clock / 5 clock
combo2_14 equ 000D00000h ; 4 clock / 5 clock
combo2_15 equ 000E00000h ; 5 clock / 5 clock
combo2_16 equ 000F00000h ; 6 clock / 5 clock
The code in the lead topic has been updated with the combination codes.
I've have now generated a working PCI Substitute ROM for the ABIT AM2 board NF-M2 nView, to set the
Async Latency to 8ns, Twr to 5T, and Trrd to 4T. Settings were verified using Systool. This verifies the

"combo" code works…
The "combo" code again:
My brief code for this test. Note the Vendor and Device ID are for the ABIT NF-M2 nView only:
code:
;-----------------
;-----PCI ROM Header--------
;
---------------——
ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512
VENDOR_ID equ 10DEh ; PCI Vendor ID (must match your ethernet vendor id)
; exp: 10DE = nVidia
DEVICE_ID equ 0269h ; PCI Device ID (must match your ethernet devicie id)
; exp: 0269h = NF-M2 NIC
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
db 0 ; checksum, to be filled in later
TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header
PCIHDR: DB 'PCIR' ; PCI data structure signature
DW VENDOR_ID ; vendor ID (must match real PCI
device)
DW DEVICE_ID ; device ID (must match real PCI
device)
DW 0 ; pointer to vital product data (0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI 2.1)

DB 2,0,0 ; PCI device class code (2=network
ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86 compitable)
DB 80h ; last image indicator
DW 0 ; reserved
PNPHDR: DB '$PnP' ; PnP data structure signature
DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in 16B blocks)
DW 0 ; offset to next header (0-none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-none)
DW 0 ; disconnect vector (0-none)
DW 0 ; bootstrap entry vector (0-none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-none)
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
mov eax,08000C294h ; cDRAM Configuration High address
mov ebx,000000080h ; copy register data for Async Latency 8nsec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFFF0Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C288h ; DRAM Timing Low address
mov ebx,000A00000h ; copy register data for Twr: 5T/Trrd: 4T
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FF0FFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax

popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
The PCI Option ROM has the very nice feature of being able to be disabled/enabled in the BIOS.
The 2 most common PCI BIOS Modules are the "RAID" module and the "Boot Agent" module. While most
folks do not want to loose the "RAID", I'll concentrate on using the "Boot Agent" module…
All newer boards today have at least 1 LAN onboard. In most BIOS, there is a option to disable or enable
that LAN… . Many BIOS also have a 2nd option that allows the system to boot from the LAN. This is called
the "Boot Agent", and is normally set to "Disable"…
In the BIOS itself, the ROM that is loosely referred to as the "LAN Module", is actually the "Boot Agent"
module and is not needed for the LAN to function properly. It can be removed and the LAN functions
perfectly. So because of this, the "Boot Agent" module is the perfect module to "release" with Cbrom32,
and replace with our PCI Substitution ROM.
The reasoning behind this is, if we created a PCI ROM that sets memory timings that hang the system, a
simple CMOS clear will return the system to "normal" operation. This of course assumes the "Boot Agent"
is set to disable as the default. If it is not, a simple Modbin6 session fixes that.
The only AMI BIOS I tried the PCI Substitution ROM on, disabled both the normal LAN and the "Boot
Agent" with a single BIOS option. But, if the PCI Option ROM works and it is what you want, the LAN
would be turned on anyhow…
The AM2 Patcher code has been updated to split the combined timing codes… . As I test, fix and rewrite
the Code, I'll keep the lead topic updated. Here's the new code in the simplified form for Async Latency
and the split Twr and Trrd:

Here's the code for the PCI Substitute Option ROM used on the DFI Infinity UltraII-M2. This is the code
that went into the 8UM2D7_8.bin BIOS:
code:
;-----------------

;-----PCI ROM Header--------
;
---------------——
ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512
VENDOR_ID equ 10DEh ; PCI Vendor ID (must match your ethernet vendor id)
; exp: 10DE = nVidia
DEVICE_ID equ 0057h ; PCI Device ID (must match your ethernet devicie id)
; exp: 0057h = DFI UltraII-M2 NIC
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
db 0 ; checksum, to be filled in later
TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header
PCIHDR: DB 'PCIR' ; PCI data structure signature
DW VENDOR_ID ; vendor ID (must match real PCI
device)
DW DEVICE_ID ; device ID (must match real PCI
device)
DW 0 ; pointer to vital product data (0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI 2.1)
DB 2,0,0 ; PCI device class code (2=network
ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86 compitable)
DB 80h ; last image indicator
DW 0 ; reserved
PNPHDR: DB '$PnP' ; PnP data structure signature
DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in 16B blocks)
DW 0 ; offset to next header (0-none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-none)
DW 0 ; disconnect vector (0-none)
DW 0 ; bootstrap entry vector (0-none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-none)
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp

mov eax,08000C28Ch ; DRAM Timing High address
mov ebx,000000C00h ; copy register data for twrrd: 3clks
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFF3FFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C28Ch ; DRAM Timing High address
mov ebx,000002000h ; copy register data for twrwr: 3clks
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFCFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C28Ch ; DRAM Timing High address
mov ebx,000004000h ; copy register data for trdrd: 3clks
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFF3FFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C28Ch ; DRAM Timing High address
mov ebx,000020000h ; copy register data for Tref: 7.8usec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFCFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
;-----------------
mov eax,08000C294h ; DRAM Configuration High address
mov ebx,000000090h ; copy register data for Async Latency 9nsec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFFF0Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C294h ; DRAM Configuration High address
mov ebx,007000000h ; copy register data for Bypass max: 7 memclk cycles
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0F0FFFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C294h ; DRAM Configuration High address
mov ebx,0A0000000h ; copy register data for 4 bank act window: 17 memclk
cycles

mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,00FFFFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
;-----------------
mov eax,08000C2A0h ; DRAM Controller Miscellaneous Data address
mov ebx,0000001C0h ; copy register data for Idle cycle limit: 256 cycles
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFFE3Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Updated the AM2 Rom Patcher to 1.0.5 dated 6/9/07.
This update adds Trfc0, Trfc1, Trfc2, Trfc3, Read/Write Queue Bypass, and Dynamic Idle Cycle Limit
Enable.
This update came out of work where we made a PCI Code-Injection ROM that changed 20 memory
timings. I wrote Dwords to each of the 5 register that control the memory timings. The Dwords contained
all the necessary data changes for the required timings. Here's the source code without sub-routines. And
the timings it sets:
CAS: 5T
tRCD: 5T
tRP: 5T

tRAS: 15T
tRC: 24T
Command Rate: 2T
tRRD: 5T
tWR: 5T
tWTR: 3T
tREF: 7.9us
Drive Strength: Normal
Max Async Latency: 9ns
Idle Cycle Limit: 32
Dynamic Idle Cycle: Enable
Queue Bypass: 15
Read/Write Queue Bypass: 16
Trfc0: 195ns
Trfc1: 195ns
Trfc2: 195ns
Trfc3: 195ns
Here's the code that would be put into either a PCI ROM or a ISA ROM:
Download Source Code here.

Updated code 9/7/07: Trcd and Trtp masks were not exactly correct.
Remember, the information presented may not work for you. If you are not
comfortable modifying BIOS's and flashing them, do not attempt to modify
them.

Building Your Own AWARD ISA Option ROM
The information presented here is the product of several weeks of trial, error, and
brushing up on Assembly Language programming. A huge thanks must go out mainly to
Master Pinczakko and tictac for their articles, help, and review of assembly source code
posted in the Building an AWARD ISA ROM Discussion Thread. While there is a tendency
by Internet BIOS modders to keep what they know a deep dark secret, both Pinczakko
and Tictac are more then willing to share their knowledge.
Also unknowingly providing help from their mod BIOS, programs, and articles, are
Sideeffect, Borg Number One, H.Oda, and the authors of FASM, A64Tweaker, CBID, CPU-
Z, Systool, and the many other free programs that are available on the internet. Their
unpaid work effort is truly appreciated
Questions, comments, etc, should be posted in Building an AWARD ISA ROM Discussion
Thread.
Note that while the process seems relatively simple, one needs to know the registers,
ports, and data for each option the ROM is going to modify upon bootup. That
information can be gotten from the code posted in Tictac's AMD Athlon 64 DDR ROM
Patcher Rev 3.0 topic or in the AMD AM2 DDR2 ROM Patcher Version 1.0.4 topic. Also in
that topic are more sophisticated source code examples that may be better to use after
understanding this presentation. Source code for the 3 working versions is here…
The first thing that must be known about a ISA Option ROM is it's format. From
Pinczakko's endless articles on the subject of BIOS modding, a ISA Option ROM must
follow the following format:
1. It's a plain binary file.
2. It's size is a multiple of 512 bytes.
3. It's header has the following format:
A. 55AAh ;This is the 1st and 2nd byte, its a bootable code sign.
B. xxh ;This is the 3rd byte, where xx is the hex number that indicate the size of the rom
in a multiple of 512 bytes, e.g. for a 512 bytes rom it will be 01h.
C. jmp ;Commonly this is the 4th through 6th byte, usually this is a near jump instruction
that invoke the real initialization code of the rom.
D. retf (return far);The last byte in the header, it invokes a far return to pass the
program execution back to the main bios, you can invoke it in the initialization part as
well, so this does not have to be in the header.
4. Its byte checksum is exactly zero.
A. After all of its bytes are summed and goes through modulo 100h operation, it's equal
to zero. In practice this should be pretty easy, for example if you use Hexworkshop
version 3.0 or higher, from the Tools menu, choose generate checksum and choose byte
(8 bit) checksum to see the checksum of your file, for a valid rom it should be equal to
zero. This can be very handy if you want to turn your plain binary file into a valid rom,
just open the file using Hexworkshop or similar hex editor program and then generate the

checksum of your xxxx.com file, if it's not zero then subtract the remainder of your
current checksum from 100h, this is the byte you need to insert into your plain binary
file, for example if the remainder shown in Hexworkshop is 0x2C then you will need to
add D4 into your file. I usually add this byte into the end of the program to compensate
for the checksum needed, after the return instruction, so that it won't interfere with your
main code.
It should be noted that the ISA, PCI, VGA, and GV3 ROM modules also have the same
basic format.
Also note that a ISA Option ROM configured for the same register as a PCI Option ROM,
will override the PCI Option ROM. The ISA Option ROM is executed last.
Thanks to Tictac, here is simple working source code that can be assembled with FASM
and inserted in a BIOS and addresses the memory registers accessible on the PCI bus. As
shown, the example sets Tref to 200Mhz 15.6usec and Async Latency to 8nsec, but can
be modified for any timing setting available. All ISA ROM format conditions above are
satisfied:
code:
use16 ; 16bit mode
ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512
bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp ; clear the registers for use by
pushing the data down
mov eax,08000C28Ch ; copy register address DRAM Timing
High
mov ebx,000000300h ; copy register data for 200Mhz
15.6usec
mov dx,0CF8h ; set port address

out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; receive data
and eax,0FFFFE0FFh ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
mov eax,08000C294h ; copy register address DRAM Config
High
mov ebx,000000008h ; copy register data for Async Latency
8nsec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; receive data
and eax,0FFFFFFF0h ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd ; clear the registers and return data
as we are finished
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until
we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
While the above code is fairly straight forward, I found that to completely understand
what is taking place, this simpler code was easier to understand for a Assembly novice.
To use this code, the checksum must be patched after being compiled with FASM, but is
presented for information only. The above code is the complete code that should be used:
code:

use16 ; compile in 16 bit mode
ROMStart: ; start our code
db 55h ; fulfill header requirements
db 0AAh ; fulfill header requirements
db 01h ; ROM will be 1 block of 512 bytes
call main ; go to main routine
retf ; return far to system bios routine
xchg ax, bp ; exchange data
; * ** MAIN R O U T I N E *
times (256)-($-$$) db 0 ; locate Main routine at 100h
main:
pushad ; push data on stack down
;* ** Set Tref to 15.6usec
**
mov eax, 8000C28Ch ; copy register address DRAM Timing
High
mov dx, 0CF8h ; set port address
out dx, eax ; send address through the port
mov dx, 0CFCh ; set port data
in eax, dx ; receive data
and eax, 0FFFFE0FFh ; set data in eax with Tref bit=0h
or eax, 00000300h ; set data in eax Tref bit=3h(200Mhz
15.6usec)
out dx, eax ; send new data through port data
;
* ** Set Async Latency to 8nsec ;
mov eax, 8000C294h ; copy register address DRAM Config
High
mov dx, 0CF8h ; set port address
out dx, eax ; send address through the port
mov dx, 0CFCh ; set port data
in eax, dx ; receive data
and eax, 0FFFFFFF0h ; set data in eax with Async Latency
bit=0h
or eax, 00000008h ; set data in eax Async Latency bit=8h
(8nsec)
out dx, eax ; send new data through port data
;
**
popad ; pop data from top of stack
retn ; return near
times (512-$) db 0 ; pad rom with 0h to end
ROMEnd: ; end our code
Remember you are using this information entirely at your own risk. The
information presented may not work for you. If you are not comfortable
modifying BIOS's and flashing them, do not attempt to modify them. You
must be able to recover from a "bad" flash.

Building Your Own AWARD Substitute PCI Option ROM
The information presented here is the product of several weeks of trial, error with both
the PCI and ISA Option ROM projects, and brushing up on Assembly Language
programming. Again, a huge thanks must go out mainly to Master Pinczakko and tictac
for their articles, help, and review of assembly source code posted in the Building an
AWARD PCI ROM Discussion Thread. While there is a tendency by Internet BIOS modders
to keep what they know a deep dark secret, both Pinczakko and Tictac are more then
willing to share their knowledge.
Also unknowingly providing help from their mod BIOS, programs, and articles, are
Sideeffect, Borg Number One, H.Oda, and the authors of FASM, A64Tweaker, CBID, CPU-
Z, Systool, and the many other free programs that are available on the internet. Their
unpaid work effort is truly appreciated
Questions, comments, etc, should be posted in Building an AWARD PCI ROM Discussion
Thread. In addition, some work has been performed on a Substitute PCI Option ROM for
an AMI BIOS. That discussion is here…
Note that while the process seems relatively simple, one needs to know the registers,
ports, and data for each option the ROM is going to modify upon bootup. That
information can be gotten from the code posted in Tictac's AMD Athlon 64 DDR ROM
Patcher Rev 3.0 topic or in the AMD AM2 DDR2 ROM Patcher Version 1.0.4 topic. Also in
that topic are more sophisticated source code examples that may be better to use after
understanding this presentation along with the PCI Header code. Source code for the 3
working versions is here…
It appears that the best PCI ROM module to substitute a PCI Option ROM for, is the LAN
module. My experience in generating mod BIOS's with PCI Option ROM's added, has
shown that the LAN module in the BIOS is the Network Boot Agent and in many cases,
does not control the LAN at all. Replacing the LAN module does not seem to render the
onboard Ethernet inoperative in most cases. The other PCI Module that could be a target
of the PCI Option ROM is the RAID module, but many users are using RAID and would
not want to give up that feature. Tictac has released a few mod BIOS's where he added
the code to the LAN module, so that no features were lost. The details of that technique
are discussed in the Building an AWARD PCI ROM Using Code Injection.
The first thing that must be known about a PCI Option ROM is it's format. From
Pinczakko's endless articles on the subject of BIOS modding, a PCI Option ROM must
follow the same format as the ISA Option ROM. Here's the required format:
1. It's a plain binary file.
2. It's size is a multiple of 512 bytes.
3. It's header has the following format:
A. 55AAh ;This is the 1st and 2nd byte, its a bootable code sign.
B. xxh ;This is the 3rd byte, where xx is the hex number that indicate the size of the rom

in a multiple of 512 bytes, e.g. for a 512 bytes rom it will be 01h.
C. jmp ;Commonly this is the 4th through 6th byte, usually this is a near jump instruction
that invoke the real initialization code of the rom.
D. retf (return far);The last byte in the header, it invokes a far return to pass the
program execution back to the main bios, you can invoke it in the initialization part as
well, so this does not have to be in the header.
4. Its byte checksum is exactly zero.
A. After all of its bytes are summed and goes through modulo 100h operation, it's equal
to zero. In practice this should be pretty easy, for example if you use Hexworkshop
version 3.0 or higher, from the Tools menu, choose generate checksum and choose byte
(8 bit) checksum to see the checksum of your file, for a valid rom it should be equal to
zero. This can be very handy if you want to turn your plain binary file into a valid rom,
just open the file using Hexworkshop or similar hex editor program and then generate the
checksum of your xxxx.com file, if it's not zero then subtract the remainder of your
current checksum from 100h, this is the byte you need to insert into your plain binary
file, for example if the remainder shown in Hexworkshop is 0x2C then you will need to
add D4 into your file. I usually add this byte into the end of the program to compensate
for the checksum needed, after the return instruction, so that it won't interfere with your
main code.
5. The PCI Option ROM has the additional requirement of having the Vendor and
Device ID codes in the header. The ID's of your PCI module can be found using the
techniques described in the Building an AWARD PCI ROM Discussion Thread.
It should be noted the PCI, ISA, VGA, and GV3 ROM modules all have the same basic
format requirements of items 1-4.
Note that a ISA Option ROM configured for the same register as a PCI Option ROM, will
override the PCI Option ROM. The ISA Option ROM is executed last.
Thanks to Tictac, here is simple working source code that can be assembled with FASM
and inserted into a BIOS. The code is the PCI substitution method for the ABIT AN8-Ultra.
This example will set Tref to 15.6us and Async Latency to 7ns, but can be modified to
preset any timing available. The NIC ROM module will be removed and the compiled code
will be inserted in place of the NIC ROM. This code is combination of Tictac's PCI ROM
Header and my really brief ISA ROM code and addresses the memory registers accessible
on the PCI bus. All PCI ROM format conditions above are satisfied:
code:
;-----------------
;-----PCI ROM
Header
--------
;
---------------——
ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512

bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512
VENDOR_ID equ 10DEh ; PCI Vendor ID (must match your
ethernet vendor id)
; exp: 10DE = nVidia
DEVICE_ID equ 0057h ; PCI Device ID (must match your
ethernet devicie id)
; exp: 0057h = nforce4 CK804 NIC
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
db 0 ; checksum, to be filled in later
TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header
PCIHDR: DB 'PCIR' ; PCI data structure signature
DW VENDOR_ID ; vendor ID (must
match real PCI device)
DW DEVICE_ID ; device ID (must
match real PCI device)
DW 0 ; pointer to vital product data
(0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI
2.1)
DB 2,0,0 ; PCI device class code
(2=network ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86
compitable)
DB 80h ; last image indicator
DW 0 ; reserved
PNPHDR: DB '$PnP' ; PnP data structure signature
DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in
16B blocks)
DW 0 ; offset to next header (0-
none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network
ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,
cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-

none)
DW 0 ; disconnect vector (0-
none)
DW 0 ; bootstrap entry vector (0-
none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-
none)
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
mov eax,08000C28Ch ; copy register address DRAM Timing
High
mov ebx,000000300h ; copy register data for 200Mhz
15.6usec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx
and eax,0FFFFE0FFh ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
mov eax,08000C294h ; copy register address DRAM Config
High
mov ebx,000000007h ; copy register data for Async Latency
7nsec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx
and eax,0FFFFFFF0h ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until

we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Remember, the information presented may not work for you. If
you are not comfortable modifying BIOS's and flashing them, do
not attempt to modify them.

Building Your Own AWARD PCI Option ROM Using Code Injection
The information presented here is the product of many months of trial, error with both the PCI and ISA Option ROM
projects, plus reading Assembly Language Programming tutorials and manuals over and over. Again, a huge thanks
must go out mainly to Master Pinczakko and tictac for their articles, help, and review of assembly source code posted in
the Building an AWARD PCI ROM Discussion Thread. While there is a tendency by Internet BIOS modders to keep what
they know a deep dark secret, both Pinczakko and Tictac are more then willing to share their knowledge.
Also unknowingly providing help from their mod BIOS, programs, and articles, are Sideeffect, Borg Number One, H.Oda,
and the authors of FASM, A64Tweaker, CBID, CPU-Z, Systool, and the many other free programs that are available on
the internet. Their unpaid work effort is truly appreciated
Questions, comments, etc, should be posted in Building an AWARD PCI ROM Discussion Thread.
Note that while the process seems relatively simple, one needs to know the registers, ports, and data for each option
the ROM is going to modify upon bootup. That information can be gotten from the code posted in Tictac's AMD Athlon
64 DDR ROM Patcher Rev 3.0 topic or in the AMD AM2 DDR2 ROM Patcher Version 1.0.4 topic. Also in that topic are
more sophisticated source code examples that may be better to use after understanding this presentation along with the
PCI Header code.
As with the PCI Substitute Option ROM, it appears that the best PCI ROM module to inject code into is the LAN module.
My experience in generating mod BIOS's with PCI Option ROM's added, has shown that the LAN module in the BIOS is
the Network Boot Agent and in most cases, does not control the LAN at all. Injecting code into the LAN module does not
render the onboard Ethernet inoperative at all. The other PCI Module that could be a target of a injected PCI Option
ROM is the RAID module, but many users are using RAID and would not want that feature fiddled with. Tictac has
released a few mod BIOS's where he added the code to the LAN module, so that no features were lost. We will use one
of those BIOS as a template and approach this project from a mechanical standpoint. In other words, we'll show you
what to do with a minimum of theory. Remember Intel(IBM Compatible) uses what is called "Little Endian" Notation.
That means that the least significant digits are displayed first. So, the decimal number 65172, which is FE94h in Hex,
will be displayed as 94FE in the binary file.
The first thing that must be known about any PCI Option ROM is it's format. From Pinczakko's priceless articles on the
subject of BIOS modding, a PCI Option ROM must follow the same format as the ISA Option ROM. Here's the required
format:
1. It's a plain binary file.
2. It's size is a multiple of 512 bytes.
3. It's header has the following format:
A. 55AAh ;This is the 1st and 2nd byte, its a bootable code sign.
B. xxh ;This is the 3rd byte, where xx is the hex number that indicate the size of the rom in a multiple of 512 bytes, e.
g. for a 512 bytes rom it will be 01h.
C. jmp ;Commonly this is the 4th through 6th byte, usually this is a near jump instruction that invoke the real
initialization code of the rom. Some BIOS use a call instruction here.
D. retf (return far);The last byte in the header, it invokes a far return to pass the program execution back to the main
bios, you can invoke it in the initialization part as well, so this does not have to be in the header.
4. Its byte checksum is exactly zero.
A. After all of its bytes are summed and goes through modulo 100h operation, it's equal to zero. In practice this should
be pretty easy, for example if you use Hexworkshop version 3.0 or higher, from the Tools menu, choose generate
checksum and choose byte (8 bit) checksum to see the checksum of your file, for a valid rom it should be equal to zero.
This can be very handy if you want to turn your plain binary file into a valid rom, just open the file using Hexworkshop
or similar hex editor program and then generate the checksum of your xxxx.com file, if it's not zero then subtract the
remainder of your current checksum from 100h, this is the byte you need to insert into your plain binary file, for
example if the remainder shown in Hexworkshop is 0x2C then you will need to add D4 into your file. I usually add this
byte into the end of the program to compensate for the checksum needed, after the return instruction, so that it won't
interfere with your main code.
5. The PCI Option ROM has the additional requirement of having the Vendor and Device ID codes in the
header. The ID's of your PCI module can be found using the techniques described in the Building an AWARD PCI ROM
Discussion Thread.

All of the requirements for the PCI ROM Module are met with the LAN Boot ROM, as it is a valid PCI ROM. Only the jump
instruction in the header will be changed.
It should be noted the PCI, ISA, VGA, and GV3 ROM modules all have the same basic format requirements of items 1-4.
The "Code Injection" method could probably be performed on any of these that exist in the subject BIOS, if they have
enough room. But that is the subject for another topic and will not be pursued here.
Note that a ISA Option ROM configured for the same register as a PCI Option ROM, will override the PCI Option ROM.
The ISA Option ROM is executed last.
Here is a flow diagram of the original PCI ROM along side the modified PCI ROM:
The BIOS we're working with is for the ABIT AN8 Ultra, a S939 system. In the top window, we see the 55AAh that is the
signature of the PCI ROM. The 80h indicates that the ROM has 128 blocks of 512 bytes. After the 80h byte, in the
middle window, we see the new jump instruction(E9h). This jump instruction is telling the system to start executing
code at 1D5Ah(7514) lines after this instruction. That works out to be code line 1D60h. The next Hex Byte, CBh, is a far
return instruction, to return the system to the next line of code the called this PCI ROM. The code in the bottom window
allows the PCI LAN Boot ROM to function normally and was not changed from the originally code. All we are changing is
the jump instruction that previously was a call(E8) instruction, and the destination of the instruction to be our new code.

In the top window, we see the 55AAh that is the signature of the PCI ROM, plus the size byte, and the jump instruction
which is highlighted. In the middle window, we see a jump instruction to 0126h lines of code after the instruction. The
exact reason for this stop and jump again, is not known, but will be used for now. In the next day or 2, I'll try this
method without this step. I'm sure the reason will become apparent.
Edit: Jumping right to the added code works just fine. No need to stop and jump again. The follow-on instructions will
jump right to the added code.
The bottom window shows the destination of the last jump command. Calculating the exact number of lines to jump, is
easy. Subtract the next byte address after the jump instruction, from the required destination. That gives us the hex
value for the jump instruction.
Example: 1D60h-6h=1D5Ah and 1E89h-1D63h=126h
Note that the above block diagram and 2 screen shots and their code/values, are for reference only, and are not to be
viewed as usable code. They are posted for information and reference only. The next post below, will show how to
generate usable code.

Building Your Own AWARD PCI Option ROM Using Code Injection: Brief Method
To successfully generate a PCI ROM using "Code Injection", we really need to start at the beginning and do some
groundwork first. To begin with, we must look at the call instruction code that is in the header of the unmodded LAN
Boot ROM, to see where it's directing the system to. Note that on some BIOS, this is a jump instruction. I'll detail what
that means to the added code a little later:
Using IDA Disassembler, we see that the code E83B0Fh is a call to 0F41h. What this means to our added code is, at the
end of our code, we must call 0F41h to allow the system to continue on normally after executing our added code. Had
this been a jump instruction, then we would add a jump to 0F41h at the end of our added code. Remember Intel(IBM
Compatible) uses what is called "Little Endian" Notation. That means that the least significant digits are displayed first.
So, the decimal number 3899, which is 0F3Bh in Hex, will be displayed as 3B0F in the binary file. IDA tries to
disassemble the first 2 bytes 55AAh, but doesn't know that they are only a signature. Ignore this.

This is the Source Code for the Hex Code I added to the LAN Boot ROM. It sets the Tref to 15.6usec @ 200Mhz, and sets
the Async Latency to 8nsec. I chose these 2 memory timings for testing purposes only. I know my system at default
sets these 2 timings to other settings, so when the LAN Boot is Enabled, I can check to see that my modified ROM is
working. Note that this code is not "complete enough" to be used for any thing other then PCI Code Injection. Also,
there are many ways to write the source code that may be smaller, or more sophisticated, but that is not the intent of
this thread, and will not be pursued. I chose the most straight forward, simple approach that works for me.
Here in the top window, we have compiled the Source Code using FASM. The only thing missing is the call to 0F41h, and
the far return, CBh. The method to calculate the value for the call instruction to get to 0F41h, is a little different then
what we did in the lead topic. We need an address that is beyond the file size, so that it wraps around and becomes
0F41h. To do this, we simply subtract the next address after the instruction, from 10F41h. So we get 10F41h-
1EE2h=F05Fh. The bottom window shows the code copied and pasted into the ROM. The call, it's address, and the far
return, have been typed in manually after the highlighted code. It's: E85FF0CBh.

Here I've changed the 4 bytes of our header to jump to the added code that was injected at 1F89h. This will always be a
jump instruction regardless of what it was originally. The bottom window shows the code added into the ROM and the
address where it starts. Calculating the exact number of lines to jump, is easy. Subtract the next byte address after the
jump instruction, from the required destination. That gives us the hex value for the jump instruction. In this case:
1E89h-0006h=1E83h

Here we see the new code added in, starting at 1E89h. Note that Hex Workshop displays the starting location of the
code at the bottom left. 1E89h is the destination of the header jump instruction that is shown in the top window of the
previous picture. The code could have been added any place there is room, just as long as the jump and call instruction
addresses, were calculated based on the new location.
Here I have disassembled the modded LAN Boot ROM to ensure that everything has the correct addresses. All that is left
to do is put the LAN Boot ROM back into my BIOS, and fire her up!

The code injected into the BIOS worked as expected and testing verified that everything was working just fine. I will
update this thread as I find out any additional or new information.
Here's code for changing several AM2 memory timings using DWords containing several memory data sets. This code
was injected into the LAN Boot module of a AM2 motherboard BIOS. Note that using subroutines for common code,
could reduce the size of the binary code, probably 2:1…
Here's copy and pasteable code:
code:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
mov eax,08000C288h ; DRAM Timing Low address
mov ebx,000EDC224h ; register data for: Cas, Trcd, Trp, Tras,
; Trc, Trrd, Twr
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FF000CC8h ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C28Ch ; cDRAM Timing High address
mov ebx,06DB20300h ; register data for: Twtr, Tref, Trfc
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0000CFCFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C290h ; DRAM Configuration Low address
mov ebx,000000080h ; register data for: Drive Strength Normal

mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFFF7Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C294h ; DRAM Configuration High address
mov ebx,000100090h ; register data for: Async & CRC
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFEFFF0Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
mov eax,08000C2A0h ; DRAM Miscellaneous address
mov ebx,00000012Ch ; register data for: Idle Cycle,
; Dynamic Idle, Queue Bypass, Trfc0-3
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFFE13h ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
Remember, the information presented may not work for you. If you are not
comfortable modifying BIOS's and flashing them, do not attempt to modify them.

The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN
This topic's purpose is to bring together all the information learned in the Hacking The _ITEM.BIN Module And It's Interaction With
_EN_CODE.BIN topic. While much was discussed in that topic that makes the subject appear very complex, the interaction between
the 2 subject BIOS modules is quite straightforward. That original thread should be read and re-read to fully understand what is being
presented. A huge thanks must go out to luk1999 for his initial work on this subject…
Background:
The Biostar 965PT BIOS has gross errors in the settings of Twr, Twtr, Trrd, and Trtp. The actual memory timing does not agree with
the BIOS setting. This error is in all released 965PT BIOS to date.
Problem:
Not being able to fix the timings in the system bios module, I could just re-label the timings. But in the _EN_CODE.BIN module, all 4
memory settings in question, use only 2 set of timing labels, so it was impossible to re-label the settings, as the amount of error was
different for each option.
Solution:
I created 2 new sets of labels at the end of the _EN_CODE.BIN module, and added the addresses of those labels to a new address list:
0000 0200 E05F 3060
At the beginning of the _EN_CODE.BIN module, I added the address, 6082h, of the new address list, to the main address list.(In the
follow up post, I had found something pointing to this address and had to move it.)
Then in the _ITEM.BIN module, I changed the addresses, that the addresses of the corrected labels exist at.
Put it all back together and it works perfectly!

Details:
This is the _ITEM.BIN module. Top window is unchanged from the original. The bottom has 1B0Fh changed to 0010h at the beginning
and 1B0Fh changed to 0110h at the end. 1B0Fh is the 28th address in the 16th group. I changed it to the 1st address in the 17th
group. 00h is always the 1st position.

Here in the _EN_CODE.BIN module, we see the address of the 17th group. It was blank, and I made it 6082h, because that is where I
added the labels addresses.

Here we see the labels that I added to the end of the _EN_CODE.BIN module.

And finally the addresses of the labels. Note that in the 6082h address is 0200h which indicates that there are 2 labels in this group or
address list. The first address is 5FE0h and I have highlighted that address in the label area in the bottom window.
This is a breakdown of a typical _ITEM.BIN module sequence and what the entries mean:

This is a little block diagram or flowchart showing how the addresses of the labels are defined. Remember 00h is the 1st address:

Here is something that can drive you bonkers! After modding 4-5 BIOS the exact same way, a mod of a older version, works, but has
"[v_]" or "[t_]" scattered about when entering the BIOS! The BIOS works, but the display is all fouled up. I checked the addresses
several times and I finally noticed this:
The very 1st address in the _EN_CODE.bin main address list, points to 0594h in this BIOS module. And the 1st address in that
address list, points back to 0030h. 0030h is empty right now, but not for long

Turns out that 0030h is where I need to add an address, that points to a new address list!

Solution is to change the 3000h that is in address 0594h, to a higher number. I used 4000h as that was in the newer BIOS modules…
Evidently, the 1st address in the 1st address list, points to a address where the data in the _EN_CODE.bin module can start to be
read. If there is data in that address, visual junk is displayed throughout the BIOS. This is only noticed when entering the BIOS
running on a system. It's not noticed in Modbin…

BIOS Without _ITEM.BIN
Some BIOS do not have a setup0 module, named "_ITEM.BIN" The BIOS GUI information is in the system bios
module. It appears that these BIOS do not open with the latest Modbin6 program, even though they are AWARD
BIOS.
In the screen shot below of a Gigabyte P965 BIOS, I highlighted in yellow all the FFFFh bytes which are the 5th and
6th byte in a _ITEM.BIN sequence. I have highlighted in black, a typical 25 byte sequence that appears to follow
the standard _ITEM.BIN sequence format:
Modifying any sequence in the system bios module is a little different then when the data in in the _ITEM.BIN
module. While the system bios module can be extracted several ways and modified quite easily, it is near
impossible to replace. See How to Change Original.tmp in Award6.0 bios, Quick Guide from tictac for a technique to
replace/modify the system bios module.
A modification of a BIOS that has no _item.bin is documented here:
Adding a New Item to a BIOS Without _ITEM.BIN

Item Help
In my BIOS mods, I try to add "Item Help" verbiage in the right hand pane of the BIOS window. One of the issues is formatting that
information. It tends to run on, wrap around, and sometimes loses a character when wrapping around..
In doing a mod, I just noticed that "0Bh" in front of a word, causes a "line break" to the verbiage. Here's a screenie of an example.
The verbiage starts at 6393h, the "line breaks" are highlighted in yellow. The address pointer, 9363h, is also circled:

[Press Enter]
From our work outlined in the Hacking The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN topic, I have found a way to
add the [Press Enter] on new branches!
Here I have selected 4 Items to put under a unused branch:

Adding New Unused Items, And Moving Them Safely
One of the issues we run into when adding new Items to a BIOS, is having enough blank or unused Items to use for the new Items we
want to add. Most all BIOS I have looked at have 5 unused Items directly under "Maximum Payload Size", which in turn is under "PNP/PCI
Configuration". But some BIOS do not have 5 and/or we need more then that. I have been using "Full Screen Logo" and if necessary "EPA
Logo", but only after removing their modules from the BIOS so they don't randomly come on. luk1999 has found that adding one of the
unused sequences to the area shown below, adds a new unused Item under directly under "Maximum Payload Size":

Most of the BIOS I looked at only have 1 sequence before the end of the _item.bin module, but still, adding the code in
the same place, adds 1 more new unused Item. Here I've added the new sequence in:

Original BIOS:
And the result is 1 more unused Item:

Now to Moving Them Around
Another idea from luk1999 for "safe" moving of Items is to simply change their "Position Code" to that of where we want the
new Items to show up in the BIOS. This requires going in and finding the "Position Code" of Items already in the area where
we want our new Items to show up.
A quick reminder of the sequence definition:
Here I've copy and pasted the 5 unused Item sequences into Notepad so that I can visualize them easier. Note that all have
the same "Position Code" of C603h:
Simply changing those "Position Codes" will move the Item to the desired area and this can be done after the mod is in, or at
the very beginning of the mod process. I suggest moving the Item(s) early on just in case there is some issue.

For this test, I selected the top unused branch:

Pressing "alt+C" inserts the 4 Items under that branch, but without a heading label:

I've gone in and labeled it "Spread Spectrums" and enabled it as it was disabled by default:
Now for the [Press Enter] I found an existing branch and disabled it to be able to locate it's sequence. I've found some very
interesting things in it's sequence. First off. it only has 1 mask. Secondly, it has 00h for the number of selections, but has a selection
label address that ultimately points to the "Press Enter" label in it's _EN_CODE.BIN module:

I edited the new "Spread Spectrums" branch sequence to have 00h selections and have it's label address pointer point to where "Press
Enter" is located in the _en_code.bin module.
Success! We now can make an unused branch look just like every other branch The branch can be moved to a logical place at this
point, if desired.

1' -
tilia f
/PCI Cowtipratiois
lilt Display Tint [PCI Slot] Item hell
leset Cewtipeatlot Data [Disabled]
Menu Level /
a ces Coattollel by [Arto(ESCI)]
x IRQ Resources Press Enter
PCIAM Palette Sso! [Disabled]
it, ** PCI Express relative items **
Muc Payl�Sise 146961
Spmd Sit (Press Eaterl

Remember you are using this information entirely at your own risk. The information presented may not work
for you. If you are not comfortable modifying BIOS's and flashing them, do not attempt to modify them. You
must be able to recover from a "bad" flash.

How to Change Original.tmp in Award6.0 bios, Quick Guide from tictac…
tictac:
This hack had been done to ABIT AN7 bios version 15… which is not possible to hack it with Modbin/Modhack
All u need to have is Hex Editor & Cbrom
- After done modding Original.tmp file
lets say the file we mod is AN7.bin (biosfile) & original tmp file (System.bin)
- install it to the bios file:
cbrom an7.bin /other 5000:0 system.bin
-then open the AN7.bin with hex editor
-copy the new award compression for the file we just install
-save it to blank file(System.bin Award compression)
-Then release all bios module from an7.bin
-until only System Bios file left there
-now re-open back an7.bin the bios file with hex editor
-copy the hack system.bin compression file and paste it ON original temp file in Abit.bin
-then re-install back all bios module
-this way… Cbrom will do the checksum
Pinczakko:
Just a little bit clarifications to remove the "myths" regarding this method.
code:
cbrom an7.bin /other 5000:0 system.bin
says to compress system.bin into LZH format and decompress it to segment 5000h during the decompression stage of the BIOS
code execution. In unmodified Award BIOS binary, segment 5000h is also the destination of the system BIOS's decompression
process. Examine the LZH header if you're still confused. - You should understand what I'm saying if you have read my BIOS
reverse engineering article -

quote:
- install it to the bios file:
cbrom an7.bin /other 5000:0 system.bin
-then open the AN7.bin with hex editor
-copy the new award compression for the file we just install
-save it to blank file(System.bin Award compression)
These steps compress the modified system BIOS. Probably the same as using LHA compressor with modified header. I'll check it
later
Anyway, in a little better English terms
quote:
This hack had been done to ABIT AN7 bios version 15… which was not possible to hack with Modbin/Modhack
All u need to have are Hex Editor & Cbrom
- After you're done modding Original.tmp file,
lets say the file you mod is AN7.bin (the biosfile) & its original_tmp/system_bios file is system.bin
- install it the system_bios/original_tmp file to the bios file:
cbrom an7.bin /other 5000:0 system.bin
-then open the AN7.bin (which is injected with the modified system_bios file) with hex editor
-copy the new compressed system_bios in the injected AN7.bin and save it to blank binary file, named system.bin.
-Then release all bios module from an7.bin
-until only system_bios file left there

-now re-open back an7.bin the bios file with hex editor
-copy the hacked system.bin file (note: this file is compressed in the previous steps) and paste it ON the original_tmp/
system_bios file in Abit.bin
-then re-install back all bios module with Cbrom
-this way… Cbrom will do the checksum
offtopic: Hei tictac I thought you're joining an English course in Bali . I'm just kidding man. Good work, as always
Polygon:
OK, let's try this and see where it leads…

Here's a basic Award BIOS before releasing any modules. Note the System BIOS is at the top of the list:

Here I've released all the modules and only the System BIOS is left:
The first thing I'll try is putting all the modules back in to see if the process can even be done. Note that while I have deleted
(released) all the modules with CBRom155, I used BIOS Information Tool(Bit) to extract them all at once.
I put all the modules back in the same order until I got to the Logo. I realized I had installed the Logo.bmp for the EPA bitmap. So
I release the EPA Logo and reinserted both at the end. Here's what it looks like now. Notice my file names are slightly different
then the original. Saves typing time :

J1 temp4.txt - Notepad - 1131 2 j (
File Edit Format Help
cb1S5 V1.55 [10/12/OS Release] (C)Phoenix Technologies 2001-2005
**
507. bi n BIOS component
No. Item-Name Original-Size Compressed-Size Original-File-Name
0.
1. XGROUP CODE OE930h(58.30K)09D38h(39.30K)awardext.rom
2. CPU micro code 02000h(8.OOK)00390h(0.89K)cpucode.bin
3. ACPI table 0603Ah(24.06K)020DEh(8.22K)acpitbl.bin
4. YGROUP ROM OB400h(45.OOK)048BAh(18.18K)awardeyt.rom
5. GROUP ROM[ 0] 058EOh(22.22K)026B1h(9.67K)_en_code.bin
6. SETUPO 01BCOh(6.94K)OOB9Dh(2.90K)_item.bin
7. OEMO CODE ODB90h(54.89K)00825h(2.04K)bsmicode.rom
8. PCI ROM[A] OCOOOh(48.OOK)06FD8h(27.96K)nvraid.rom
9. VGA ROM[1] OE200h(56.SOK)OAOE4h(40.22K)c5lvga7.rom
10. OEM1 CODE OOBAFh(2.92K)006D3h(1.71K)pmu.bin
11. GV3 03EA2h(15.66K)01025h(4.04K)agesacpu.rom
12. PCI ROM[B] OAOOOh(40.OOK)OSF99h(23.90K)rtspxe_m.lom
13. OEM3 CODE 00090h(0.14K)OOOAFh(0.17K)memsetup.rom
14. OEM2 CODE 17888h(94.88K)09ADBh(38.71K)memtest.rom
15. OEM4 CODE 01350h(4.83K)OODB7h(3.43K)su_flash.rom
16. MIB ROM OOA40h(2.56K)0051Eh(1.28K)cru5lam2.txt
17. EPA LOGO 0168Ch(5.64K)002AAh(0.67K)awardbmp.bmp
18. LOGO BitMap 756OCh(469.51K)OBF2Ch(47.79K)biosnew5.bmp
Totalcompress code space =SAOOOh(360.OOK)
Totalcompressed code size = 57C80h(351.13K)
Remaincompress code space = 02380h(8.88K)
* **
NVMM 4.071.0301/23/07 00 Start Offset => 0, End Offset => 4b00 *
** Micro code Information **
Update ID CPUID I Update ID CPUID I Update ID CPUID I Update ID CPUID
J

As a test I opened the BIOS in Modbin6 and it seems perfectly normal. I'll flash it tonight when I get home just as a sanity check,
but it should be fine.
Remember CBRom fixes the checksum, and I used CBRom155. I recently ran into a BIOS mod that required all the modules to be
in the original order or it would not boot. So I figured this would work…
Next is to see what I can do with the shell that I had made a copy of…
I tried following the steps outlined and ran into some minor trouble. I'll outline what happened, step-by-step, with the solutions I
used:
quote:
This hack had been done to ABIT AN7 bios version 15… which was not possible to hack with Modbin/Modhack OK
All u need to have are Hex Editor & Cbrom OK
- After you're done modding Original.tmp file,
lets say the file you mod is AN7.bin (the biosfile) & its original_tmp/system_bios file is system.bin OK
- install it the system_bios/original_tmp file to the bios file:
cbrom an7.bin /other 5000:0 system.bin 1st problem: the original BIOS does not have enough room to do this. I had
to release the Logo and Memtest for it to fit. I have successfully been installing the system.bin to a BIOS with all the
modules removed. The added system.bin immediately follows the original system bios(or the last module) with a single
FFh byte separating them when installed into the BIOS with all the modules removed.

I notice that CBRom generates a file called bios.rom that is the system.bin compressed and is exactly what has been
added to the BIOS. That bios.rom can be used as the "copy" and the BIOS that has 2 system bios can be deleted.

-then open the AN7.bin (which is injected with the modified system_bios file) with hex editor OK
-copy the new compressed system_bios in the injected AN7.bin and save it to blank binary file, named system.bin. OK,
this would save it as compressed, but it could be Copied N' Pasted right from here. Really no need for a blank binary
file or this step. The bios.rom file is the exact, compressed module we need.
-Then release all bios module from an7.bin OK
-until only system_bios file left there OK
-now re-open back an7.bin the bios file with hex editor OK
-copy the hacked system.bin file (note: this file is compressed in the previous steps) and paste it ON the original_tmp/
system_bios file in Abit.bin OK, but I would add: Make sure the exact number of bytes is pasted over, that is copied, or
there may be problems. Also if the new system bios is smaller, and there is code remaining from the old system bios,
change those bytes to FFh bytes. If the new system bios is bigger, no problem. I check the block size of the bios.rom,
and go to 10000h in the shell BIOS. I then select a block size from 10000h to the bios.rom size+1, and paste. The
block size+1 takes care of 00h not being counted in the block size of bios.rom
-then re-install back all bios module with Cbrom OK, we removed all the modules before copying the compressed
modified system.bin to the main BIOS. Reinstalling them all not only fixes the checksum, but takes care of the fact
that the system bios is usually not the exact same size as the original, and puts everything in the correct place.
-this way… Cbrom will do the checksum OK
Post any questions on this technique in the How to Change Original.tmp in Award6 bios, Quick Guide from tictac: Discussion Topic
For a step-by-step tutorial, see: Adding a New Item to a BIOS Without _ITEM.BIN
Remember, the information presented may not work for you. If you are not comfortable
modifing BIOS's and flashing them, do not attempt to modify them.

Adding a New Item To an AWARD BIOS
Credits:
This project could not have been accomplished without the help and knowledge of Pinczakko , tictac, luk1999! Thanks guy's!
Limitations:
It must be noted that as of this posting, only AMD powered boards, with AWARD BIOS, have been successfully modified by
the following technique. Intel Options ROMs are not working at this time. Also, due to the nature of BIOS from ASUS,
Gigabyte, and MSI, this technique may not be possible with those boards.
Post questions about this technique in the: Adding a New Item To an AWARD BIOS Discussion Thread
Prerequisites:
To be able to understand and perform this technique, you must have a total understanding of the interaction between the
_ITEM.BIN and _EN_CODE.BIN BIOS modules. The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN topic must be
studied and understood by making some changes to test mods BIOS. Without the 110% understanding of these 2 BIOS
modules, a new Item cannot be generated successfully.
The ability to write source code for an ISA Option ROM is also a must. This means you must be familiar with Assembly
Language and AMD data sheets for A64 and AM2 processors. See Building Your Own AWARD ISA Option ROM Write some
code, compile it, and make sure it works in your BIOS.
The 2 requirements above, assume that you are adept at using Modbin6, CBROM32, Hex Editor, IDA Disassembler, and FASM
or another compiler, at a minimum.
Another informative thread is the CMOS Registers(Indexes) Discussion Thread
Basics:
To add a brand new Item, we will use 1 of these 5 unused branches. Almost every BIOS I have looked at has at least 3 and in
this exact position. Later on in this topic, we will look at how to add a Item if your BIOS has no unused branch available.

Here I have gone into the top blank branch and changed the visibility from "Disable" to "Normal" This will allow me to find the
25 Byte sequence in the _ITEM.BIN module for this branch using the compare tool of Hex Workshop.
Here's the detailed definition of a typical _ITEM.BIN 25 byte sequence. Note the 1st byte and it's possible values. Our branch
went from "Disable"(08h) to "Normal"(00h):
I found that coping the sequences of interest to notepad, and separating the bytes with spaces, the work effort was much
easier. Especially with the address of the 1st byte, labeled in front of the sequence:

Here's a screen shot of the 25 byte sequence in the _ITEM.BIN of interest. I'm using the compare tool of Hex Workshop, on a
unmodded _ITEM.BIN module(top) and a modified _ITEM.BIN module(bottom). In the top window the highlighted byte is the
08h indicating a "Disabled" branch or Item. Note in the bottom window, that byte is now 00h due to the modification by
Modbin6:
In this screen shot, I have edited the _ITEM.BIN module sequence for a theoretical BIOS that has no CAS Item. In red are
the changed bytes that correspond to the added Item label and settings labels, shown in the edited _EN_CODE.BIN module
below this. I chose CMOS register 20h, after a search for 0020h revealed 20h was not being used as a index register. The
mask of 0Fh just sets everything in 20h to 0000b, other then the bit that is of interest. To enable the new Item to work
correctly, the 1st mask, 0Fh, must also be added.
To understand what I'm doing here, you must understand the material presented in the topic:
The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN: Adding a Little More Space

Here's the _EN_CODE.BIN module before adding the labels needed:
Here's the _EN_CODE.BIN module after adding the labels needed along with their addresses in "Little Endian" notation:

Here is the finished BIOS less the Option ROM. I believe the pictures speak for themselves. All that's left to do is Insert the
Option ROM, and move the Item to where we want it.

Now that we have the BIOS set up for the new Item "CAS", we will look at the code for the ISA Option ROM that will read the
CMOS settings and set the CAS register as we desire.
Here's the heart of the code to read the CMOS register and set the correct CAS timing. It is heavily commented and has no
constants, or subroutines for ease of review. Be aware that the code while technically correct, is for a theoretical system and
not for a current system as AM2 does not have Cas 2 or 2.5 and does have several more timing options. The code is for
reference only and intended to be used as a starting point or template for your code…
This is copy and pasteable complete code that can be used as a starting point or template for your code.
code:
use16 ; 16bit mode
ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp ; clear the registers for use by pushing the data down
;
;
; Set Memory Cas Biostar 6100-550 N5TAA207 BIOS

; _ITEM.BIN sequence: 0380h
; CMOS: 020h, mask: 0Fh
;
;
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 03h ;compare data to 03h
jne cas2 ;jump if not equal 0000.0011b
jmp codend ;Auto selected, got to end
cas2:
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 00h ;compare data to 00h
jne cas25 ;jump if not equal 0000.0000b
;set CAS=2
mov eax,08000C288h ;copy register address DRAM Timing Low Register
mov ebx,000000000h ;copy register data for CAS 2T
mov dx,0CF8h ;set port address
out dx,eax ;send address through the port
mov dx,0CFCh ;set port data
in eax,dx ;get data
and eax,0FFFFFFF8h ;mask data
or eax,ebx ;increase data
out dx,eax ;send data through port data
;
cas25:
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 01h ;compare data to 01h
jne cas3 ;jump if not equal 0000.0001b
;set CAS=2.5
mov eax,08000C288h ;copy register address DRAM Timing Low Register
mov ebx,000000001h ;copy register data for CAS 2.5T
mov dx,0CF8h ;set port address
out dx,eax ;send address through the port
mov dx,0CFCh ;set port data
in eax,dx ;get data
and eax,0FFFFFFF8h ;mask data
or eax,ebx ;increase data
out dx,eax ;send data through port data
;
cas3:
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 02h ;compare data to 02h
jne cas25 ;jump if not equal 0000.0010b
;set CAS=3

mov eax,08000C288h ;copy register address DRAM Timing Low Register
mov ebx,000000002h ;copy register data for CAS 3T
mov dx,0CF8h ;set port address
out dx,eax ;send address through the port
mov dx,0CFCh ;set port data
in eax,dx ;get data
and eax,0FFFFFFF8h ;mask data
or eax,ebx ;increase data
out dx,eax ;send data through port data
;
codend:
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd ; clear the registers and return data as we are finished
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:

Here's the disassembled code that gives it a check that everything is reasonably correct:

If we did everything correctly, we now have a brand new Item added to our BIOS I didn't bother to move it so it can be
seen to still be under "Maximum Payload", which is where our unused branch was located. And again, even though I actually
did every step to create a new Item, this instructional topic is/was not intended to be a actually mod. It is for reference only.

Be aware that to become accomplished at this technique, has taken me more then a year of intensive BIOS study, literally
hundreds of lesser BIOS modifications, and at least 50 hot flashes. It is something that will not be learned overnight as every
BIOS modification discipline there is, is required to be understood 110%…
I'm working on a Mod BIOS that will add 2 new Items. I might as well photo document the steps, as 2 or more items require
some special considerations
I located the 2 sequences for the 2 branches I'll use by making them visable by using Modbin, and then doing a compare
using Hex Workshop.

This is the last address group in the _EN_CODE.BIN module. It has 35h entries. It is after this code, I will add our Item and
Setting labels.
Here I've added the labels for 2 new Items and their settings. Address list number 35h, changes to 39h. The 4 addresses of
the new labels are added. The address of a label is the Hex position, in "Little Endian" notation, of the 1st letter. The address
of the settings is the 1st letter of the 1st setting label only.

Back to the _ITEM.BIN module to add all the required addresses, defaults, and mask/index/mask. Note that our original 25
byte sequences only had 1 mask, but 2 are needed. 1 for the Setup defaults and 1 for the BIOS defaults. Also note that the
2nd 25 byte sequence has the mask 70h, while the 1st 25 byte sequence uses 07h. The 1st 25 byte sequence will write to the
1st 4 bits of the 20h register, and the 2nd 25 byte sequence will write to the 2nd 4 bits of the 20h register. I did a search of
the _ITEM.BIN module for Hex sequence 0020h, to make sure 20h was not being used already.
A quick test in Modbin shows the 2 new Items now labeled, and in the original location right now.

The first new Item is Read/Write Queue Bypass. I set the defaults to 16x:

The 2nd new Item is Tref. I've set the defaults to cesu8.7|zhM002#cesu8.7|zhM002.

And a quick flash shows the new Items and settings.
The BIOS has no ISA Option ROM at this point, so the settings don't do anything.

Here I have moved the 2 new Items to the Advanced Chipset Features window. I can't put them under the "DRAM
Configuration" heading because everything in there can be disabled. Adding an Item into a linked window corrupts the BIOS.
So above the "DRAM Configuration" is going to have to do.

And now the source code for the ISA Option ROM that reads the CMOS register and sets the timings accordingly. The code
could be written with constants, and subroutines, but for me it's easier to trouble shoot like this.(8-12-07 Code Updated: Tref

data in AMD data sheet may be incorrect! Source code fixed.)(10-22-07 Source Code Updated: Add jump over all code if
DDRII Timing Item in BIOS is disabled and add Idle Cycle Limit code to fix non-working Item):
code:
use16 ; 16bit mode
ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
pushfd
push eax
push ebx
push ecx
push dx
;====================================================================
; R/W Queue Bypass & Tref AN8_21.RH BIOS
; _ITEM.BIN: 031Ch CMOS: 021h mask: 07h R/W Queue Bypass
; CMOS: 021h mask: F0h Tref
; CMOS: 088H mask: E0h Idle Cycle Limit
; _ITEM.BIN: 0F92h CMOS: 81h mask: 30h DRAM Config(Auto, SPD, Manual)
;====================================================================
;READ MEMORY TIMING STATE
mov al, 81h ;index - 81h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 30h ;mask 0011.0000
cmp al, 00h
je codend ;jump if equal 0000.0000, Auto Selected
;reading from cmos
mov al, 021h ;index - 021h
out 072h, al ;send register offset
in al, 073h ;fetch data
mov cl, al ;save for later
and al, 07h ;mask 0000.0111
cmp al, 00h ;
je TREF ;jump if equal 00h, Auto selected
cmp al, 01h ;
je RWQ2 ;jump if equal 01h
cmp al, 02h ;
je RWQ4 ;jump if equal 02h
cmp al, 03h ;
je RWQ8 ;jump if equal 03h
cmp al, 04h ;
je RWQ16 ;jump if equal 04h
jmp TREF ;jump to TREF
RWQ2:
;set Queue Bypass 2x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,000000000h ; 2X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;

jmp TREF
RWQ4:
;set Queue Bypass 4x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,000004000h ; 4X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
RWQ8:
;set Queue Bypass 8x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,000008000h ; 8X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
RWQ16:
;set Queue Bypass 16x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,00000C000h ; 16X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;
;====================================================================
TREF:
mov al, cl ;use saved data
and al,0F0h ;mask 1111.0000
cmp al, 00h
je ICL ;jump if equal 0000.0000, AUTO SELECTED
cmp al, 10h
je 6.51|001ferT#6.51|001ferT ;jump if equal 0001.0000
cmp al, 20h
je 6.51|331ferT#6.51|331ferT ;jump if equal 0010.0000
cmp al, 30h
je 6.51|661ferT#6.51|661ferT ;jump if equal 0011.0000
cmp al, 40h
je 6.51|002ferT#6.51|002ferT ;jump if equal 0100.0000
cmp al, 50h
je 8.7|001ferT#8.7|001ferT ;jump if equal 0101.0000
cmp al, 60h
je 8.7|331ferT#8.7|331ferT ;jump if equal 0110.0000
cmp al, 70h
je 8.7|661ferT#8.7|661ferT ;jump if equal 0111.0000
cmp al, 80h
je 8.7|002ferT#8.7|002ferT ;jump if equal 1000.0000
cmp al, 90h
je 9.3|001ferT#9.3|001ferT ;jump if equal 1001.0000
cmp al, 0A0h
je 9.3|331ferT#9.3|331ferT ;jump if equal 1010.0000
cmp al, 0B0h
je 9.3|661ferT#9.3|661ferT ;jump if equal 1011.0000
cmp al, 0C0h
je 9.3|002ferT#9.3|002ferT ;jump if equal 1100.0000
jmp ICL
6.51|001ferT#6.51|001ferT:
;set Tref=cesu6.51|zhM001#cesu6.51|zhM001
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000000h ; cesu6.51|zhM001#cesu6.51|zhM001
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;

or eax,ebx ;
out dx,eax ;
jmp ICL
6.51|331ferT#6.51|331ferT:
;set Tref=cesu6.51|zhM331#cesu6.51|zhM331
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000100h ; cesu6.51|zhM331#cesu6.51|zhM331
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
6.51|661ferT#6.51|661ferT:
;set Tref=cesu6.51|zhM661#cesu6.51|zhM661
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000200h ; cesu6.51|zhM661#cesu6.51|zhM661
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
6.51|002ferT#6.51|002ferT:
;set Tref=cesu6.51|zhM002#cesu6.51|zhM002
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000300h ; cesu6.51|zhM002#cesu6.51|zhM002
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
;===============================================================================
8.7|001ferT#8.7|001ferT:
;set Tref=cesu8.7|zhM001#cesu8.7|zhM001
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000400h ; cesu8.7|zhM001#cesu8.7|zhM001
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL
8.7|331ferT#8.7|331ferT:
;set Tref=cesu8.7|zhM331#cesu8.7|zhM331
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000500h ; cesu8.7|zhM331#cesu8.7|zhM331
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
8.7|661ferT#8.7|661ferT:
;set Tref=cesu8.7|zhM661#cesu8.7|zhM661
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000600h ; cesu8.7|zhM661#cesu8.7|zhM661
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;

and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
8.7|002ferT#8.7|002ferT:
;set Tref=cesu8.7|zhM002#cesu8.7|zhM002
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000700h ; cesu8.7|zhM002#cesu8.7|zhM002
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
;===============================================================================
9.3|001ferT#9.3|001ferT:
;set Tref=cesu9.3|zhM001#cesu9.3|zhM001
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000800h ; cesu9.3|zhM001#cesu9.3|zhM001
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL
9.3|331ferT#9.3|331ferT:
;set Tref=cesu9.3|zhM331#cesu9.3|zhM331
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000900h ; cesu9.3|zhM331#cesu9.3|zhM331
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
9.3|661ferT#9.3|661ferT:
;set Tref=cesu9.3|zhM661#cesu9.3|zhM661
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000A00h ; cesu9.3|zhM661#cesu9.3|zhM661
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
9.3|002ferT#9.3|002ferT:
;set Tref=cesu9.3|zhM002#cesu9.3|zhM002
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000B00h ; cesu9.3|zhM002#cesu9.3|zhM002
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
ICL:
;reading from cmos
mov al, 088h ;index - 0??h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0E0h ;mask 1110.0000
cmp al, 00h

je ICL0 ;jump if equal 0000.0000
cmp al, 20h
je ICL4 ;jump if equal 0010.0000
cmp al, 40h
je ICL8 ;jump if equal 0100.0000
cmp al, 60h
je ICL16 ;jump if equal 0110.0000
cmp al, 80h
je ICL32 ;jump if equal 1000.0000
cmp al, 0A0h
je ICL64 ;jump if equal 1010.0000
cmp al, 0C0h
je ICL128 ;jump if equal 1100.0000
cmp al, 0E0h
je ICL256 ;jump if equal 1110.0000
jmp codend
ICL0:
;set Idle Cycle Limit 0X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000000000h ; 0X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL4:
;set Idle Cycle Limit 4X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000010000h ; 4X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL8:
;set Idle Cycle Limit 8X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000020000h ; 8X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL16:
;set Idle Cycle Limit 16X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000030000h ; 16X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL32:
;set Idle Cycle Limit 32X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000040000h ; 32X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;

out dx,eax ;
jmp codend
ICL64:
;set Idle Cycle Limit 64X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000050000h ; 64X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL128:
;set Idle Cycle Limit 128X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000060000h ; 128X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL256:
;set Idle Cycle Limit 256X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000070000h ; 256X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
codend:
pop dx
pop ecx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
The Mod BIOS adding new Items Tref and R/W Queue Bypass, is working perfectly. The BIOS is released publicly:
2 New Items Added: RHCF Advanced Mod AN821RHX Bios for AN8 Series!

One last set of tweaks and this mod BIOS is finished! I increased the number of settings by 1 each, and added "Auto" as the
first setting/label in the list. The 00h Hex number in the CMOS register 20h, will be read by the ISA ROM, and just bypass all
comparators and not change what the original BIOS set for these 2 memory settings. I also added the right hand pane Item
descriptions for both newly added Items.

Here's another use for this advanced technique…
An AM2 BIOS that overclocks well, has the Async Latency apparently not working. It is always 6ns no matter what the BIOS
is set for. We find the Async Latency sequence in the _ITEM.BIN module and note that the index is A3h and the mask is
0Fh…

We then write the code for an ISA Option ROM that reads the A3h CMOS register and sets the Async Latency accordingly.
Testing of the mod BIOS finds the Async Latency now working. Some issues about clearing the CMOS were discovered later
on, but the basic concept for this fix is valid. Here is the source code for that ROM:
code:
use16 ; 16bit mode
ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
pushfd
push eax
push ebx

push ecx
push dx
;====================================================================
; Async Latency Fix CR51A505.RHx BIOS
; _ITEM.BIN: 1168h
; CMOS: 0A3h
; mask: 0Fh
;====================================================================
;reading from cmos
mov al, 0A3h ;index - 0A3h
out 072h, al ;send register offset
in al, 073h ;fetch data
mov cl, al ;save for later
and al, 0Fh ;mask 0000.1111
cmp al, 00h
je AUTO ;jump if equal 0000.0000
cmp al, 01h
je ASL1 ;jump if equal 0000.0001
cmp al, 02h
je ASL2 ;jump if equal 0000.0010
cmp al, 03h
je ASL3 ;jump if equal 0000.0011
cmp al, 04h
je ASL4 ;jump if equal 0000.0100
cmp al, 05h
je ASL5 ;jump if equal 0000.0101
cmp al, 06h
je ASL6 ;jump if equal 0000.0110
cmp al, 07h
je ASL7 ;jump if equal 0000.0111
cmp al, 08h
je ASL8 ;jump if equal 0000.1000
cmp al, 09h
je ASL9 ;jump if equal 0000.1001
cmp al, 0Ah
je ASL10 ;jump if equal 0000.1010
cmp al, 0Bh
je ASL11 ;jump if equal 0000.1011
cmp al, 0Ch
je ASL12 ;jump if equal 0000.1100
cmp al, 0Dh
je ASL13 ;jump if equal 0000.1101
cmp al, 0Eh
je ASL14 ;jump if equal 0000.1110
cmp al, 0Fh
je ASL15 ;jump if equal 0000.1111
jmp codend
AUTO:
;set Async Lat 6T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000060h ; Async Lat 6T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL1:
;set Async Lat 1T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000010h ; Async Lat 1T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend

ASL2:
;set Async Lat 2T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000020h ; Async Lat 2T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL3:
;set Async Lat 3T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000030h ; Async Lat 3T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL4:
;set Async Lat 4T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000040h ; Async Lat 4T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL5:
;set Async Lat 5T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000050h ; Async Lat 5T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL6:
;set Async Lat 6T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000060h ; Async Lat 6T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL7:
;set Async Lat 7T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000070h ; Async Lat 7T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL8:

;set Async Lat 8T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000080h ; Async Lat 8T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL9:
;set Async Lat 9T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000090h ; Async Lat 9T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL10:
;set Async Lat 10T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000A0h ; Async Lat 10T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL11:
;set Async Lat 11T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000B0h ; Async Lat 11T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL12:
;set Async Lat 12T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000C0h ; Async Lat 12T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL13:
;set Async Lat 13T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000D0h ; Async Lat 13T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL14:

;set Async Lat 14T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000E0h ; Async Lat 14T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL15:
;set Async Lat 15T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000F0h ; Async Lat 15T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
codend:
pop dx
pop ecx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
The Mod BIOS fixing the Async Latency Item is working perfectly, and is released publicly.
See: Rebels Haven Releases CR51A505RX Advanced Mod BIOS Series for 6100-AM2!
Here's the screen shots I made for adding 3 new Items to the Biostar 6100-AM2 BIOS. I also grouped 4 Spread Spectrum
Items under 1 new heading. The finished BIOS was released publicly in this topic: Rebels Haven Releases CR51A316.RHX
Advanced Mod BIOS: 6100-AM2: 3 New items Added!

First thing was to locate the 5 Sequences in _ITEM.BIN module. The grouping and moving was done with Modbin6 before any
mods went in. Top window is before, bottom is after the changes:
Remember the Sequence Definition Chart:

At the end of the _EN_CODE.BIN module, I added a total of 508 bytes:
All the address pointers, labels, settings, and right hand information pane data was added. I could have added the address
pointers to the list directly in front of where I added a new list starting with the highlighted 08h byte. BTW, no checksum
correction needed:
And finally the source code for the ISA Option ROM that will read the CMOS data and set the 3 new memory Items:

code:
use16 ; 16bit mode
ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
pushfd
push eax
push ebx
push ecx
push dx
;====================================================================
; Trtw, Tref, Async Latency CR51A316.RHx BIO

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License