add voodoo2_config
This commit is contained in:
parent
6413c2ef1d
commit
68fb5ba5fb
9
.gitignore
vendored
9
.gitignore
vendored
@ -3,3 +3,12 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
__pycache__
|
__pycache__
|
||||||
*.gch
|
*.gch
|
||||||
|
*.o
|
||||||
|
*.mod
|
||||||
|
*.ko
|
||||||
|
*~
|
||||||
|
*.symvers
|
||||||
|
.*
|
||||||
|
*.cmd
|
||||||
|
*.order
|
||||||
|
*.mod.c
|
@ -201,7 +201,7 @@ def render_all(rls):
|
|||||||
yield "#include <stddef.h>"
|
yield "#include <stddef.h>"
|
||||||
yield "#include <stdint.h>"
|
yield "#include <stdint.h>"
|
||||||
yield ""
|
yield ""
|
||||||
yield "typedef volatile uint32_t reg32;"
|
yield '#include "reg.h"'
|
||||||
yield ""
|
yield ""
|
||||||
yield from render_register_struct(rls, max_length)
|
yield from render_register_struct(rls, max_length)
|
||||||
yield from render_static_assert(rls, max_length)
|
yield from render_static_assert(rls, max_length)
|
||||||
|
92
gen/voodoo2_config.py
Normal file
92
gen/voodoo2_config.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import sys
|
||||||
|
from generate import renderer
|
||||||
|
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
buf = f.read()
|
||||||
|
|
||||||
|
def split_line(line):
|
||||||
|
register_name = line[0:21]
|
||||||
|
addr = line[21:44]
|
||||||
|
bits = line[44:53]
|
||||||
|
description = line[53:]
|
||||||
|
return (
|
||||||
|
register_name.strip(),
|
||||||
|
addr.strip(),
|
||||||
|
bits.strip(),
|
||||||
|
description.strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
def parse_addr(addr):
|
||||||
|
base10, base16 = addr.split()
|
||||||
|
base16 = base16.removeprefix('(').removesuffix(')')
|
||||||
|
assert int(base10, 10) == int(base16, 16)
|
||||||
|
return int(base16, 16)
|
||||||
|
|
||||||
|
def parse_bits(bits):
|
||||||
|
high, low = bits.split(":")
|
||||||
|
return int(high, 10), int(low, 10)
|
||||||
|
|
||||||
|
def parse_lines(buf):
|
||||||
|
it = map(split_line, buf.strip().split('\n'))
|
||||||
|
header = next(it)
|
||||||
|
assert header == ('Register Name', 'Addr', 'Bits', 'Description')
|
||||||
|
for register_name, addr, bits, description in it:
|
||||||
|
if register_name.lower() == "reserved":
|
||||||
|
continue
|
||||||
|
addr = parse_addr(addr)
|
||||||
|
bits = parse_bits(bits)
|
||||||
|
yield register_name, addr, bits, description
|
||||||
|
|
||||||
|
def bits_length(bits):
|
||||||
|
high, low = bits
|
||||||
|
assert (high + 1) % 8 == 0 and low == 0
|
||||||
|
length = (high + 1) // 8
|
||||||
|
return length
|
||||||
|
|
||||||
|
def reg_type(length):
|
||||||
|
if length == 1:
|
||||||
|
return "reg8"
|
||||||
|
if length == 2:
|
||||||
|
return "reg16"
|
||||||
|
if length == 3:
|
||||||
|
return "reg8"
|
||||||
|
if length == 4:
|
||||||
|
return "reg32"
|
||||||
|
assert False, length
|
||||||
|
|
||||||
|
def render_struct(buf):
|
||||||
|
next_address = 0
|
||||||
|
reserved_ix = 0
|
||||||
|
yield "struct voodoo2_config {"
|
||||||
|
lines = list(parse_lines(buf))
|
||||||
|
for register_name, addr, bits, description in lines:
|
||||||
|
if addr != next_address:
|
||||||
|
yield f"reg8 _reserved{reserved_ix}[{addr - next_address}];"
|
||||||
|
reserved_ix += 1
|
||||||
|
length = bits_length(bits)
|
||||||
|
arr = "" if length != 3 else "[3]"
|
||||||
|
yield f"{reg_type(length)} {register_name}{arr};"
|
||||||
|
next_address = addr + length
|
||||||
|
yield "};"
|
||||||
|
yield ""
|
||||||
|
for register_name, addr, bits, description in lines:
|
||||||
|
length = bits_length(bits)
|
||||||
|
arr = "" if length != 3 else "[0]"
|
||||||
|
yield f"static_assert((offsetof (struct voodoo2_config, {register_name}{arr})) == 0x{addr:02x});"
|
||||||
|
|
||||||
|
def render_all(buf):
|
||||||
|
yield "#pragma once"
|
||||||
|
yield ""
|
||||||
|
yield "#include <stddef.h>"
|
||||||
|
yield "#include <stdint.h>"
|
||||||
|
yield ""
|
||||||
|
yield '#include "reg.h"'
|
||||||
|
yield ""
|
||||||
|
yield from render_struct(buf)
|
||||||
|
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
buf = f.read()
|
||||||
|
lines = buf.split('\n')
|
||||||
|
render, out = renderer()
|
||||||
|
render(render_all(buf))
|
||||||
|
sys.stdout.write(out.getvalue())
|
24
gen/voodoo2_config.txt
Normal file
24
gen/voodoo2_config.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Register Name Addr Bits Description
|
||||||
|
Vendor_ID 0 (0x0) 15:0 3Dfx Interactive Vendor Identification
|
||||||
|
Device_ID 2 (0x2) 15:0 Device Identification
|
||||||
|
Command 4 (0x4) 15:0 PCI bus configuration
|
||||||
|
Status 6 (0x6) 15:0 PCI device status
|
||||||
|
Revision_ID 8 (0x8) 7:0 Revision Identification
|
||||||
|
Class_code 9 (0x9) 23:0 Generic functional description of PCI device
|
||||||
|
Cache_line_size 12 (0xc) 7:0 Bus Master Cache Line Size
|
||||||
|
Latency_timer 13 (0xd) 7:0 Bus Master Latency Timer
|
||||||
|
Header_type 14 (0xe) 7:0 PCI Header Type
|
||||||
|
BIST 15 (0xf) 7:0 Build In Self-Test Configuration
|
||||||
|
memBaseAddr 16 (0x10) 31:0 Memory Base Address
|
||||||
|
Reserved 20-59 (0x14-0x3b) n/a Reserved
|
||||||
|
Interrupt_line 60 (0x3c) 7:0 Interrupt Mapping
|
||||||
|
Interrupt_pin 61 (0x3d) 7:0 External Interrupt Connections
|
||||||
|
Min_gnt 62 (0x3e) 7:0 Bus Master Minimum Grant Time
|
||||||
|
Max_lat 63 (0x3f) 7:0 Bus Master Maximum Latency Time
|
||||||
|
initEnable 64 (0x40) 31:0 Allow writes to hardware initialization registers
|
||||||
|
busSnoop0 68 (0x44) 31:0 Chuck bus snooping address 1 (write only)
|
||||||
|
busSnoop1 72 (0x48) 31:0 Chuck bus snooping address 0 (write only)
|
||||||
|
cfgStatus 76 (0x4c) 31:0 Aliased memory-mapped status register
|
||||||
|
cfgScratch 80 (0x50) 31:0 Scratchpad register
|
||||||
|
siProcess 84 (0x54) 31:0 Silicon Process monitor register
|
||||||
|
Reserved 88-255 (0x58-0xff) n/a Reserved
|
149
main.c
Normal file
149
main.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "voodoo2.h"
|
||||||
|
|
||||||
|
struct name_int {
|
||||||
|
const char * name;
|
||||||
|
uint32_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
void print_registers(struct voodoo2_reg * reg)
|
||||||
|
{
|
||||||
|
const struct name_int registers[] = {
|
||||||
|
{"status", reg->status},
|
||||||
|
{"fbiInit0", reg->fbiInit0},
|
||||||
|
{"fbiInit1", reg->fbiInit1},
|
||||||
|
{"fbiInit2", reg->fbiInit2},
|
||||||
|
{"fbiInit3", reg->fbiInit3},
|
||||||
|
{"fbiInit4", reg->fbiInit4},
|
||||||
|
{"fbiInit5", reg->fbiInit5},
|
||||||
|
{"fbiInit6", reg->fbiInit6},
|
||||||
|
{"fbiInit7", reg->fbiInit7},
|
||||||
|
//
|
||||||
|
{"backPorch", reg->backPorch},
|
||||||
|
{"videoDimensions", reg->videoDimensions},
|
||||||
|
{"hSync", reg->hSync},
|
||||||
|
{"vSync", reg->vSync},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < (sizeof (registers)) / (sizeof (registers[0])); i++) {
|
||||||
|
printf("%s %08x\n", registers[i].name, registers[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wait_graphics_busy(voodoo2_reg * voodoo2)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 0; i < 4096; i++) {
|
||||||
|
if (voodoo2->status & STATUS__GRAPHICS_BUSY) {
|
||||||
|
cnt += 1;
|
||||||
|
} else {
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
if (cnt >= 3)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!"busy wait timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dac_data_read(voodoo2_reg * voodoo2,
|
||||||
|
int data,
|
||||||
|
int rs)
|
||||||
|
{
|
||||||
|
voodoo2->dacData
|
||||||
|
= DACDATA__WRITE_DATA(data)
|
||||||
|
| DACDATA__ADDRESS_2_0(rs >> 0)
|
||||||
|
| DACDATA__READ_COMMAND
|
||||||
|
| DACDATA__ADDRESS_4_3(rs >> 3)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dac_data_write(voodoo2_reg * voodoo2,
|
||||||
|
int data,
|
||||||
|
int rs)
|
||||||
|
{
|
||||||
|
voodoo2->dacData
|
||||||
|
= DACDATA__WRITE_DATA(data)
|
||||||
|
| DACDATA__ADDRESS_2_0(rs >> 0)
|
||||||
|
| DACDATA__ADDRESS_4_3(rs >> 3)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dac_write_pll_8(voodoo2_reg * voodoo2,
|
||||||
|
int address,
|
||||||
|
int parameter_m)
|
||||||
|
{
|
||||||
|
dac_data_write(voodoo2, address, DAC__RS__PLL_ADDRESS_WRITE, 0);
|
||||||
|
wait_graphics_busy(voodoo2);
|
||||||
|
|
||||||
|
dac_data_write(voodoo2, parameter_m, DAC__RS__PLL_PARAMETER, 0);
|
||||||
|
wait_graphics_busy(voodoo2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dac_write_pll_16(voodoo2_reg * voodoo2,
|
||||||
|
int address,
|
||||||
|
int parameter_m,
|
||||||
|
int parameter_n)
|
||||||
|
{
|
||||||
|
dac_data_write(voodoo2, address, DAC__RS__PLL_ADDRESS_WRITE, 0);
|
||||||
|
wait_graphics_busy(voodoo2);
|
||||||
|
|
||||||
|
dac_data_write(voodoo2, parameter_m, DAC__RS__PLL_PARAMETER, 0);
|
||||||
|
wait_graphics_busy(voodoo2);
|
||||||
|
|
||||||
|
dac_data_write(voodoo2, parameter_n, DAC__RS__PLL_PARAMETER, 0);
|
||||||
|
wait_graphics_busy(voodoo2);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct mn {
|
||||||
|
uint8_t m;
|
||||||
|
uint8_t n;
|
||||||
|
} mn_t;
|
||||||
|
|
||||||
|
static inline struct mn_t dac_read_16(voodoo2_reg * voodoo,
|
||||||
|
int address)
|
||||||
|
{
|
||||||
|
dac_data_write(base, address, DAC__RS__PLL_ADDRESS_READ);
|
||||||
|
wait_graphics_busy(base);
|
||||||
|
|
||||||
|
dac_data_read(base, 0, DAC__RS__PLL_PARAMETER);
|
||||||
|
wait_graphics_busy(base);
|
||||||
|
int m = voodoo2->fbiInit2 & 0xff;
|
||||||
|
|
||||||
|
dac_data_read(base, 0, DAC__RS__PLL_PARAMETER);
|
||||||
|
wait_graphics_busy(base);
|
||||||
|
int n = voodoo2->fbiInit2 & 0xff;
|
||||||
|
|
||||||
|
return (struct m_n){ m, n };
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const char * config = "/sys/bus/pci/devices/0000:02:0a.0/config";
|
||||||
|
int fd = open(config, O_RDWR | O_SYNC);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
const char * filename = "/sys/bus/pci/devices/0000:02:0a.0/resource0";
|
||||||
|
|
||||||
|
int fd = open(filename, O_RDWR | O_SYNC);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
uint32_t map_size = 0x4000;
|
||||||
|
|
||||||
|
off_t target_base = 0;
|
||||||
|
void * map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target_base);
|
||||||
|
assert(map_base != MAP_FAILED);
|
||||||
|
|
||||||
|
struct voodoo2_reg * reg = (struct voodoo2_reg *)map_base;
|
||||||
|
print_registers(reg);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
5
reg.h
Normal file
5
reg.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef volatile uint8_t reg8;
|
||||||
|
typedef volatile uint16_t reg16;
|
||||||
|
typedef volatile uint32_t reg32;
|
@ -3,7 +3,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef volatile uint32_t reg32;
|
#include "reg32.h"
|
||||||
|
|
||||||
|
|
||||||
struct voodoo2_reg {
|
struct voodoo2_reg {
|
||||||
|
54
voodoo2_config.h
Normal file
54
voodoo2_config.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "reg.h"
|
||||||
|
|
||||||
|
struct voodoo2_config {
|
||||||
|
reg16 Vendor_ID;
|
||||||
|
reg16 Device_ID;
|
||||||
|
reg16 Command;
|
||||||
|
reg16 Status;
|
||||||
|
reg8 Revision_ID;
|
||||||
|
reg8 Class_code[3];
|
||||||
|
reg8 Cache_line_size;
|
||||||
|
reg8 Latency_timer;
|
||||||
|
reg8 Header_type;
|
||||||
|
reg8 BIST;
|
||||||
|
reg32 memBaseAddr;
|
||||||
|
reg8 _reserved0[40];
|
||||||
|
reg8 Interrupt_line;
|
||||||
|
reg8 Interrupt_pin;
|
||||||
|
reg8 Min_gnt;
|
||||||
|
reg8 Max_lat;
|
||||||
|
reg32 initEnable;
|
||||||
|
reg32 busSnoop0;
|
||||||
|
reg32 busSnoop1;
|
||||||
|
reg32 cfgStatus;
|
||||||
|
reg32 cfgScratch;
|
||||||
|
reg32 siProcess;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Vendor_ID)) == 0x00);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Device_ID)) == 0x02);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Command)) == 0x04);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Status)) == 0x06);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Revision_ID)) == 0x08);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Class_code[0])) == 0x09);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Cache_line_size)) == 0x0c);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Latency_timer)) == 0x0d);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Header_type)) == 0x0e);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, BIST)) == 0x0f);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, memBaseAddr)) == 0x10);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Interrupt_line)) == 0x3c);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Interrupt_pin)) == 0x3d);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Min_gnt)) == 0x3e);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, Max_lat)) == 0x3f);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, initEnable)) == 0x40);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, busSnoop0)) == 0x44);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, busSnoop1)) == 0x48);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, cfgStatus)) == 0x4c);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, cfgScratch)) == 0x50);
|
||||||
|
static_assert((offsetof (struct voodoo2_config, siProcess)) == 0x54);
|
Loading…
x
Reference in New Issue
Block a user