diff --git a/.gitignore b/.gitignore index ac215f6..6c7dcd2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,12 @@ *.pyc __pycache__ *.gch +*.o +*.mod +*.ko +*~ +*.symvers +.* +*.cmd +*.order +*.mod.c \ No newline at end of file diff --git a/gen/voodoo2.py b/gen/voodoo2.py index 53cbba2..c4b3876 100644 --- a/gen/voodoo2.py +++ b/gen/voodoo2.py @@ -201,7 +201,7 @@ def render_all(rls): yield "#include " yield "#include " yield "" - yield "typedef volatile uint32_t reg32;" + yield '#include "reg.h"' yield "" yield from render_register_struct(rls, max_length) yield from render_static_assert(rls, max_length) diff --git a/gen/voodoo2_config.py b/gen/voodoo2_config.py new file mode 100644 index 0000000..5fd43c3 --- /dev/null +++ b/gen/voodoo2_config.py @@ -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 " + yield "#include " + 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()) diff --git a/gen/voodoo2_config.txt b/gen/voodoo2_config.txt new file mode 100644 index 0000000..22d0900 --- /dev/null +++ b/gen/voodoo2_config.txt @@ -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 diff --git a/main.c b/main.c new file mode 100644 index 0000000..b93d496 --- /dev/null +++ b/main.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/reg.h b/reg.h new file mode 100644 index 0000000..5d9ce13 --- /dev/null +++ b/reg.h @@ -0,0 +1,5 @@ +#pragma once + +typedef volatile uint8_t reg8; +typedef volatile uint16_t reg16; +typedef volatile uint32_t reg32; diff --git a/voodoo2.h b/voodoo2.h index 39218a7..f7b29f2 100644 --- a/voodoo2.h +++ b/voodoo2.h @@ -3,7 +3,7 @@ #include #include -typedef volatile uint32_t reg32; +#include "reg32.h" struct voodoo2_reg { diff --git a/voodoo2_config.h b/voodoo2_config.h new file mode 100644 index 0000000..49e2e90 --- /dev/null +++ b/voodoo2_config.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +#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);