Permalink
Browse files

Merge branch 'RedGuyyyy-gsu' into develop

  • Loading branch information...
mrehkopf committed Jun 4, 2018
2 parents 58f592f + bf3e1b0 commit a7420e4d3c82a281db64c952f982d75c954e8ea7
Showing with 14,682 additions and 50 deletions.
  1. +4 −0 snes/const.a65
  2. +1 −1 snes/header.a65
  3. +1 −0 snes/memmap.i65
  4. +14 −0 snes/menudata.a65
  5. +1 −1 src/Makefile
  6. +7 −1 src/cfg.c
  7. +36 −34 src/cfg.h
  8. +4 −1 src/cheat.c
  9. +4 −2 src/config
  10. +1 −0 src/fpga.h
  11. +2 −0 src/fpga_spi.c
  12. +4 −2 src/memory.c
  13. +8 −2 src/smc.c
  14. +3 −2 src/smc.h
  15. +5 −3 src/snes.c
  16. +1 −1 src/utils/genhdr.c
  17. +102 −0 verilog/sd2snes_gsu/address.v
  18. +281 −0 verilog/sd2snes_gsu/bsx.v
  19. +392 −0 verilog/sd2snes_gsu/cheat.v
  20. +52 −0 verilog/sd2snes_gsu/clk_test.v
  21. +284 −0 verilog/sd2snes_gsu/dac.v
  22. +76 −0 verilog/sd2snes_gsu/dcm.v
  23. +2,825 −0 verilog/sd2snes_gsu/gsu.v
  24. +184 −0 verilog/sd2snes_gsu/ipcore_dir/dac_buf.v
  25. +108 −0 verilog/sd2snes_gsu/ipcore_dir/dac_buf.xco
  26. +388 −0 verilog/sd2snes_gsu/ipcore_dir/dac_buf.xise
  27. +180 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_cache.v
  28. +108 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_cache.xco
  29. +74 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_cache.xise
  30. +406 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_fmult.v
  31. +68 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_fmult.xco
  32. +74 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_fmult.xise
  33. +154 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_mult.v
  34. +68 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_mult.xco
  35. +74 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_mult.xise
  36. +184 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_state.v
  37. +108 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_state.xco
  38. +74 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_state.xise
  39. +162 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_umult.v
  40. +68 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_umult.xco
  41. +74 −0 verilog/sd2snes_gsu/ipcore_dir/gsu_umult.xise
  42. +184 −0 verilog/sd2snes_gsu/ipcore_dir/msu_databuf.v
  43. +108 −0 verilog/sd2snes_gsu/ipcore_dir/msu_databuf.xco
  44. +388 −0 verilog/sd2snes_gsu/ipcore_dir/msu_databuf.xise
  45. +190 −0 verilog/sd2snes_gsu/ipcore_dir/snescmd_buf.v
  46. +108 −0 verilog/sd2snes_gsu/ipcore_dir/snescmd_buf.xco
  47. +74 −0 verilog/sd2snes_gsu/ipcore_dir/snescmd_buf.xise
  48. +190 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_datram.v
  49. +108 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_datram.xco
  50. +388 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_datram.xise
  51. +184 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_datrom.v
  52. +108 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_datrom.xco
  53. +388 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_datrom.xise
  54. +184 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_pgmrom.v
  55. +108 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_pgmrom.xco
  56. +388 −0 verilog/sd2snes_gsu/ipcore_dir/upd77c25_pgmrom.xise
  57. +637 −0 verilog/sd2snes_gsu/main.ucf
  58. +1,177 −0 verilog/sd2snes_gsu/main.v
  59. +151 −0 verilog/sd2snes_gsu/main_tf.v
  60. +605 −0 verilog/sd2snes_gsu/mcu_cmd.v
  61. +210 −0 verilog/sd2snes_gsu/msu.v
  62. +392 −0 verilog/sd2snes_gsu/rtc.v
  63. +493 −0 verilog/sd2snes_gsu/sd2snes.xise
  64. +155 −0 verilog/sd2snes_gsu/sd_dma.v
  65. +127 −0 verilog/sd2snes_gsu/spi.v
  66. +185 −0 verilog/sd2snes_gsu/srtc.v
  67. +638 −0 verilog/sd2snes_gsu/upd77c25.v
  68. +150 −0 verilog/sd2snes_gsu/updtest_tf.v
View
@@ -211,6 +211,7 @@ mtext_ingame_holdoff .byt "Initial holdoff", 0
mtext_ingame_regionpatch .byt "Auto region patch", 0
mtext_ingame_1chipbrightpatch .byt "1CHIP brightness patch", 0
mtext_chip_cx4_speed .byt "Cx4 speed", 0
mtext_chip_gsu_speed .byt "GSU speed", 0
mtext_chip_msu1_volume_boost .byt "MSU-1 volume boost", 0
mdesc_mm_last .byt "Show up to 10 most recently played games", 0
@@ -237,9 +238,12 @@ mdesc_ingame_holdoff .byt "Wait 10 seconds before enabling hook (th
mdesc_ingame_regionpatch .byt "Bypass simple region protection by games", 0
mdesk_ingame_1chipbrightpatch .byt "[EXPERIMENTAL] patch brightness on 1CHIP consoles to avoid certain artifacts", 0
mdesc_chip_cx4_speed .byt "Set speed of Cx4 soft core", 0
mdesc_chip_gsu_speed .byt "Set speed of GSU soft core", 0
mdesc_chip_msu1_volume_boost .byt "Set volume boost for MSU1 audio", 0
mdesc_cx4_speed_fast .byt "Run as fast as possible", 0
mdesc_cx4_speed_normal .byt "Run at approx. original speed", 0
mdesc_gsu_speed_fast .byt "Run as fast as possible", 0
mdesc_gsu_speed_normal .byt "Run at approx. original speed", 0
text_statusbar_keys .byt "A:Select B:Back X:Menu", 0
text_statusbar_spc .byt "B:Back", 0
View
@@ -66,7 +66,7 @@ NMI_8bit:
;*= $C0FFC0
; .byt "SD2SNES MAIN MENU "
*= $C0FFC0
.byt "SD2SNES MENU v0.1.7d "
.byt "SD2SNES MENU v0.1.7e "
; 123456789012345678901 - max 21 chars
*= $C0FFD5 .byt $31 ; rom map + speed (HiROM FastROM)
View
@@ -98,6 +98,7 @@
#define CFG_CONTROL_TYPE CFG_ADDR+$009A
#define CFG_MSU_VOLUME_BOOST CFG_ADDR+$009B
#define CFG_1CHIP_BRIGHTNESS_PATCH CFG_ADDR+$009C
#define CFG_GSU_SPEED CFG_ADDR+$009D
#define ST_RTC_VALID ST_ADDR+$0000
#define ST_NUM_RECENT_GAMES ST_ADDR+$0001
View
@@ -228,6 +228,15 @@ menu_enttab_chip:
.word !CFG_CX4_SPEED
.byt ^CFG_CX4_SPEED
.byt MTYPE_VALUE
.word !mtext_chip_gsu_speed
.byt ^mtext_chip_gsu_speed
.word !kv_gsu_speed
.byt ^kv_gsu_speed
.byt OPTTYPE_KVBYTE
.word !CFG_GSU_SPEED
.byt ^CFG_GSU_SPEED
.byt MTYPE_VALUE
.word !mtext_chip_msu1_volume_boost
.byt ^mtext_chip_msu1_volume_boost
@@ -379,6 +388,11 @@ kv_cx4_speed:
.word $0001, !text_fast : .byt ^text_fast
.word $ffff
kv_gsu_speed:
.word $0000, !text_normal : .byt ^text_normal
.word $0001, !text_fast : .byt ^text_fast
.word $ffff
kv_region:
.word $0000, !text_off : .byt ^text_off
.word $0001, !text_auto : .byt ^text_auto
View
@@ -107,7 +107,7 @@ CDEFS = -DF_OSC=$(CONFIG_MCU_FOSC)UL
# Place -I options here
CINCS =
CINCS = -Iinclude
# CPU-specific flags
View
@@ -28,7 +28,8 @@ cfg_t CFG_DEFAULT = {
.skin_name = "sd2snes.skin",
.control_type = 0,
.msu_volume_boost = 0,
.patch_1chip_brightness = 0
.patch_1chip_brightness = 0,
.gsu_speed = 0
};
cfg_t CFG;
@@ -75,6 +76,8 @@ int cfg_save() {
f_puts("\n# Enhancement chip settings\n", &file_handle);
f_printf(&file_handle, "# %s: Cx4 core speed (0: original, 1: fast, all instructions are single cycle)\n", CFG_CX4_SPEED);
f_printf(&file_handle, "%s: %d\n", CFG_CX4_SPEED, CFG.cx4_speed);
f_printf(&file_handle, "# %s: GSU core speed (0: original, 1: fast, instructions execute as fast as the implementation allows)\n", CFG_GSU_SPEED);
f_printf(&file_handle, "%s: %d\n", CFG_GSU_SPEED, CFG.gsu_speed);
f_printf(&file_handle, "# %s: MSU audio volume boost\n# (0: none; 1: +3.5dBFS; 2: +6dBFS; 3: +9.5dBFS; 4: +12dBFS)\n", CFG_MSU_VOLUME_BOOST);
f_printf(&file_handle, "%s: %d\n", CFG_MSU_VOLUME_BOOST, CFG.msu_volume_boost);
file_close();
@@ -132,6 +135,9 @@ int cfg_load() {
if(yaml_get_itemvalue(CFG_CX4_SPEED, &tok)) {
CFG.cx4_speed = tok.longvalue;
}
if(yaml_get_itemvalue(CFG_GSU_SPEED, &tok)) {
CFG.gsu_speed = tok.longvalue;
}
if(yaml_get_itemvalue(CFG_MSU_VOLUME_BOOST, &tok)) {
CFG.msu_volume_boost = tok.longvalue;
}
View
@@ -7,23 +7,24 @@
#define LAST_FILE ((const uint8_t*)"/sd2snes/lastgame.cfg")
#define LAST_FILE_BAK ((const uint8_t*)"/sd2snes/~lastgame.cfg")
#define CFG_VIDMODE_MENU ("VideoModeMenu")
#define CFG_VIDMODE_GAME ("VideoModeGame")
#define CFG_PAIR_MODE_ALLOWED ("PairModeAllowed")
#define CFG_BSX_USE_USERTIME ("BSXUseUsertime")
#define CFG_BSX_TIME ("BSXTime")
#define CFG_R213F_OVERRIDE ("R213fOverride")
#define CFG_ENABLE_IRQ_HOOK ("EnableIRQHook")
#define CFG_ENABLE_IRQ_BUTTONS ("EnableIRQButtons")
#define CFG_ENABLE_IRQ_HOLDOFF ("EnableIRQHoldoff")
#define CFG_ENABLE_SCREENSAVER ("EnableScreensaver")
#define CFG_SCREENSAVER_TIMEOUT ("ScreensaverTimeout")
#define CFG_SORT_DIRECTORIES ("SortDirectories")
#define CFG_HIDE_EXTENSIONS ("HideExtensions")
#define CFG_CX4_SPEED ("Cx4Speed")
#define CFG_SKIN_NAME ("SkinName")
#define CFG_CONTROL_TYPE ("ControlType")
#define CFG_MSU_VOLUME_BOOST ("MSUVolumeBoost")
#define CFG_VIDMODE_MENU ("VideoModeMenu")
#define CFG_VIDMODE_GAME ("VideoModeGame")
#define CFG_PAIR_MODE_ALLOWED ("PairModeAllowed")
#define CFG_BSX_USE_USERTIME ("BSXUseUsertime")
#define CFG_BSX_TIME ("BSXTime")
#define CFG_R213F_OVERRIDE ("R213fOverride")
#define CFG_ENABLE_IRQ_HOOK ("EnableIRQHook")
#define CFG_ENABLE_IRQ_BUTTONS ("EnableIRQButtons")
#define CFG_ENABLE_IRQ_HOLDOFF ("EnableIRQHoldoff")
#define CFG_ENABLE_SCREENSAVER ("EnableScreensaver")
#define CFG_SCREENSAVER_TIMEOUT ("ScreensaverTimeout")
#define CFG_SORT_DIRECTORIES ("SortDirectories")
#define CFG_HIDE_EXTENSIONS ("HideExtensions")
#define CFG_CX4_SPEED ("Cx4Speed")
#define CFG_GSU_SPEED ("GSUSpeed")
#define CFG_SKIN_NAME ("SkinName")
#define CFG_CONTROL_TYPE ("ControlType")
#define CFG_MSU_VOLUME_BOOST ("MSUVolumeBoost")
#define CFG_1CHIP_BRIGHTNESS_PATCH ("1CHIPBrightnessPatch")
typedef enum {
@@ -33,23 +34,24 @@ typedef enum {
} cfg_vidmode_t;
typedef struct __attribute__ ((__packed__)) _cfg_block {
uint8_t vidmode_menu; /* menu video mode */
uint8_t vidmode_game; /* game video mode */
uint8_t pair_mode_allowed; /* use pair mode if available */
uint8_t bsx_use_usertime; /* use user defined time for BS */
uint8_t bsx_time[12]; /* user setting for BS time (in S-RTC format)*/
uint8_t r213f_override; /* override register 213f bit 4 */
uint8_t enable_irq_hook; /* enable hook routines */
uint8_t enable_irq_buttons; /* enable in-game buttons in hook routines */
uint8_t enable_irq_holdoff; /* enable temp hook disable after reset */
uint8_t enable_screensaver; /* enable screen saver */
uint16_t screensaver_timeout; /* screensaver activate timeout in frames */
uint8_t sort_directories; /* sort directories (slower) (default: on) */
uint8_t hide_extensions; /* hide file extensions (default: off) */
uint8_t cx4_speed; /* Cx4 speed (0: original, 1: no waitstates */
uint8_t skin_name[128]; /* file name of selected skin */
uint8_t control_type; /* control type (0: A=OK, B=Cancel; 1: A=Cancel, B=OK) */
uint8_t msu_volume_boost; /* volume boost (0: none; 1=+3.5dB; 2=+6dB; 3=+9dB; 4=+12dB) */
uint8_t vidmode_menu; /* menu video mode */
uint8_t vidmode_game; /* game video mode */
uint8_t pair_mode_allowed; /* use pair mode if available */
uint8_t bsx_use_usertime; /* use user defined time for BS */
uint8_t bsx_time[12]; /* user setting for BS time (in S-RTC format)*/
uint8_t r213f_override; /* override register 213f bit 4 */
uint8_t enable_irq_hook; /* enable hook routines */
uint8_t enable_irq_buttons; /* enable in-game buttons in hook routines */
uint8_t enable_irq_holdoff; /* enable temp hook disable after reset */
uint8_t enable_screensaver; /* enable screen saver */
uint16_t screensaver_timeout; /* screensaver activate timeout in frames */
uint8_t sort_directories; /* sort directories (slower) (default: on) */
uint8_t hide_extensions; /* hide file extensions (default: off) */
uint8_t cx4_speed; /* Cx4 speed (0: original, 1: no waitstates */
uint8_t skin_name[128]; /* file name of selected skin */
uint8_t control_type; /* control type (0: A=OK, B=Cancel; 1: A=Cancel, B=OK) */
uint8_t msu_volume_boost; /* volume boost (0: none; 1=+3.5dB; 2=+6dB; 3=+9dB; 4=+12dB) */
uint8_t gsu_speed; /* GSU speed (0: original, 1: no waitstates */
uint8_t patch_1chip_brightness; /* override register 2100 bits 3-0 */
} cfg_t;
View
@@ -12,6 +12,7 @@
#include <stdlib.h>
extern cfg_t CFG;
extern snes_romprops_t romprops;
uint8_t rom_index;
uint8_t wram_index;
@@ -55,8 +56,10 @@ void cheat_program() {
printf("enable mask=%02x\n", enable_mask);
fpga_write_cheat(6, enable_mask);
cheat_enable(1);
//cheat_nmi_enable(romprops.has_gsu ? 0 : CFG.enable_irq_hook);
cheat_nmi_enable(CFG.enable_irq_hook);
cheat_irq_enable(CFG.enable_irq_hook);
//cheat_irq_enable(romprops.has_gsu ? 0 : CFG.enable_irq_hook);
cheat_irq_enable((romprops.has_gsu && !strncmp((char *)romprops.header.name, "DOOM", strlen("DOOM"))) ? 0 : CFG.enable_irq_hook);
cheat_holdoff_enable(CFG.enable_irq_holdoff);
cheat_buttons_enable(CFG.enable_irq_buttons);
cheat_wram_present(wram_index);
View
@@ -1,3 +1,5 @@
CONFIG_VERSION="0.1.7e"
CONFIG_FWVER=0x01010705
CONFIG_VERSION="0.1.7e-gsu-v10"
#CONFIG_FWVER=0x01010705
CONFIG_FWVER=0xFFFFFFEC
#CONFIG_FWVER=0x44534E53
CONFIG_MCU_FOSC=12000000
View
@@ -45,6 +45,7 @@ const uint8_t *fpga_config;
#define FPGA_CX4 ((const uint8_t*)"/sd2snes/fpga_cx4.bit")
#define FPGA_OBC1 ((const uint8_t*)"/sd2snes/fpga_obc1.bit")
#define FPGA_GSU ((const uint8_t*)"/sd2snes/fpga_gsu.bit")
#define FPGA_BASE ((const uint8_t*)"/sd2snes/fpga_base.bit")
#define FPGA_ROM ((const uint8_t*)"rom")
View
@@ -186,6 +186,8 @@ void set_dac_addr(uint16_t address) {
void set_mcu_addr(uint32_t address) {
FPGA_SELECT();
// wait for prior operations to clear out
FPGA_WAIT_RDY();
FPGA_TX_BYTE(FPGA_CMD_SETADDR | FPGA_TGT_MEM);
FPGA_TX_BYTE((address>>16)&0xff);
FPGA_TX_BYTE((address>>8)&0xff);
View
@@ -328,10 +328,12 @@ uint32_t load_rom(uint8_t* filename, uint32_t base_addr, uint8_t flags) {
set_rom_mask(rommask);
readled(0);
printf("gsu=%x gsu_sram=%x\n", romprops.has_gsu, romprops.has_gsu_sram);
if(flags & LOADROM_WITH_SRAM) {
if(romprops.ramsize_bytes) {
sram_memset(SRAM_SAVE_ADDR, romprops.ramsize_bytes, 0xFF);
migrate_and_load_srm(filename, SRAM_SAVE_ADDR);
// powerslide relies on the init value to be 00.
sram_memset(SRAM_SAVE_ADDR, romprops.ramsize_bytes, romprops.has_gsu ? 0x00 : 0xFF);
if (!romprops.has_gsu || romprops.has_gsu_sram) migrate_and_load_srm(filename, SRAM_SAVE_ADDR);
/* file not found error is ok (SRM file might not exist yet) */
if(file_res == FR_NO_FILE) file_res = 0;
saveram_crc_old = calc_sram_crc(SRAM_SAVE_ADDR, romprops.ramsize_bytes);
View
@@ -33,6 +33,7 @@
#include "snes.h"
#include "fpga.h"
#include "cfg.h"
#include "memory.h"
extern cfg_t CFG;
snes_romprops_t romprops;
@@ -69,7 +70,10 @@ void smc_id(snes_romprops_t* props) {
props->has_st0010 = 0;
props->has_cx4 = 0;
props->has_obc1 = 0;
props->has_gsu = 0;
props->has_gsu_sram = 0;
props->fpga_features = 0;
props->fpga_dspfeat = 0;
props->fpga_conf = NULL;
for(uint8_t num = 0; num < 6; num++) {
score = smc_headerscore(hdr_addr[num], header);
@@ -185,8 +189,10 @@ void smc_id(snes_romprops_t* props) {
else if (header->map == 0x20 && ((header->carttype >= 0x13 && header->carttype <= 0x15) ||
header->carttype == 0x1a)) {
props->has_gsu = 1;
props->error = MENU_ERR_NOIMPL;
props->error_param = (uint8_t*)"SuperFX";
props->has_gsu_sram = (header->carttype == 0x15 || header->carttype == 0x1a) ? 1 : 0;
props->fpga_conf = FPGA_GSU;
props->fpga_dspfeat = CFG.gsu_speed;
header->ramsize = header->expramsize & 0x7;
}
break;
View
@@ -34,7 +34,7 @@
#define DSPFW_1B ((const uint8_t*)"/sd2snes/dsp1b.bin")
#define DSPFW_ST0010 ((const uint8_t*)"/sd2snes/st0010.bin")
typedef struct _snes_header {
typedef struct __attribute__ ((__packed__)) _snes_header {
uint8_t maker[2]; /* 0xB0 */
uint8_t gamecode[4]; /* 0xB2 */
uint8_t fixed_00[7]; /* 0xB6 */
@@ -67,7 +67,7 @@ typedef struct _snes_header {
uint16_t vect_brk8; /* 0xFE */
} snes_header_t;
typedef struct _snes_romprops {
typedef struct __attribute__ ((__packed__)) _snes_romprops {
uint16_t offset; /* start of actual ROM image */
uint8_t mapper_id; /* FPGA mapper */
uint8_t pad1; /* for alignment */
@@ -84,6 +84,7 @@ typedef struct _snes_romprops {
uint8_t has_cx4; /* CX4 presence flag */
uint8_t has_obc1; /* OBC1 presence flag */
uint8_t has_gsu; /* GSU presence flag */
uint8_t has_gsu_sram; /* GSU saveram presence flag */
uint8_t has_sa1; /* SA-1 presence flag */
uint8_t has_sdd1; /* S-DD1 presence flag */
uint8_t has_spc7110; /* SPC7110 presence flag */
View
@@ -61,7 +61,7 @@ status_t ST = {
void prepare_reset() {
snes_reset(1);
delay_ms(SNES_RESET_PULSELEN_MS);
if(romprops.ramsize_bytes && fpga_test() == FPGA_TEST_TOKEN) {
if(romprops.ramsize_bytes && (!romprops.has_gsu || romprops.has_gsu_sram) && fpga_test() == FPGA_TEST_TOKEN) {
writeled(1);
save_srm(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
writeled(0);
@@ -186,7 +186,7 @@ uint8_t get_snes_reset_state(void) {
uint32_t diffcount = 0, samecount = 0, didnotsave = 0, save_failed = 0, last_save_failed = 0;
uint8_t sram_valid = 0;
uint8_t snes_main_loop() {
if(romprops.ramsize_bytes) {
if(romprops.ramsize_bytes && (!romprops.has_gsu || romprops.has_gsu_sram)) {
saveram_crc = calc_sram_crc(SRAM_SAVE_ADDR, romprops.ramsize_bytes);
sram_valid = sram_reliable();
if(crc_valid && sram_valid) {
@@ -220,7 +220,9 @@ uint8_t snes_main_loop() {
last_save_failed = save_failed;
save_failed = file_res ? 1 : 0;
didnotsave = save_failed ? 25 : 0;
writeled(!last_save_failed);
// this used to be !last_save_failed which seemed odd. I would think we would want to leave the light
// on when there is a fail, but it must have been there for a reason.
writeled(romprops.has_gsu ? last_save_failed : !last_save_failed);
}
saveram_crc_old = saveram_crc;
}
View
@@ -73,7 +73,7 @@ int main(int argc, char **argv) {
return 1;
}
char *remaining = NULL;
uint32_t version = (uint32_t)strtol(argv[3], &remaining, 0);
uint32_t version = (uint32_t)strtoul(argv[3], &remaining, 0);
if(*remaining) {
printf("could not parse version number (remaining portion: %s)\n", remaining);
fclose(f);
Oops, something went wrong.

0 comments on commit a7420e4

Please sign in to comment.