Jump to content

TheMole

Members
  • Content Count

    855
  • Joined

  • Last visited

Everything posted by TheMole

  1. Have you tried looking at the contents of one of those formatted disks that threw error 38 in a working system yet? Perhaps with a sector editor or some such? Maybe you can find something that points you in the right direction. Error 38 would seem to indicate some unknown error while reading, so it might be that the disk actually does get formatted but something goes wrong during the validation step (if that even exists)?
  2. Yeah, sorry, I know it's not exactly as in Scramble, I was just referring to the little 'hick-up' you see in Scramble when loading levels (which I think in Scramble is perfectly fine, but I'm not sure it would work for Alex Kidd, especially given the fact that it will need to load longer since it's loading from disk).
  3. Thanks for asking! Unfortunately I haven't had the time to spend anything more than half an hour here or there on coding projects, and I'm at a bit of a difficult point with Alex Kidd where I'm running up against memory (and speed) limitations that require a more concentrated effort. I have been thinking about possible ways forward though, so when I do find some time, I have a bunch of things to try. One of the avenues I'm considering is making the game cartridge-based while still requiring the 32k memory expansion and disk system, with part of the code running off the cartridge and part running from the memory expansion. That should give me the additional 8k of memory that I need but would require a physical cart release for anyone to be able to play it on real iron (or a supercart, I guess). Another alternative is to simply do some mid-level loading of data from disk (kinda like in TI Scramble), but Alex Kidd doesn't have forced scrolling, so I don't know how well that would work.
  4. You're right, I miscalculated, It needs roughly 5k. The BML is initialized at 80x80 pixels, but I should've used 40x80 for my calculations since I'm using fat pixels. So, the effect requires an offscreen buffer of 40x80 bytes (not nibbles), so 3200 bytes. And the BML layer itself needs half of that (nibbles instead of bytes), so another 1600 bytes adding up to 4800 bytes. The program itself is around 300 bytes, so we need 5100 bytes in total for the fire effect and not 9900 like I originally calculated using an 80x80 buffer. So yes, it should be possible to fit in a bitmap image. Plenty of colors still available, since I'm only using one of 4 available 16-color palettes. Just need to assign a different palette to the BML. Do you have the original for the picture somewhere?
  5. No worries, I just plugged in a C function that I'd used somewhere else before. Is it correct that the timers you added in favor of the RNG are not available to the GPU?
  6. Thanks . It should be possible to put some graphics around the fire, but not something that was output by Tursi's convert9918a (the fire effect runs completely in VRAM, and requires almost 10k of memory; a bitmap image requires 12k, so you can't have both at the same time in the F18A's 18k). Something photorealistic is probably out of the question, but character mode graphics should be doable though, perhaps even in ECM3 mode... if you want to design something in Magellan, I'd be happy to include it for you.
  7. You can't, it's all C code that gets compiled by GCC. The GPU routines are in gpucode.c, get compiled to binary format (to gpucode.o, which gets transformed to gpucode.bin) and then turned into a header file via bin2h to end up as an array of bytes in gpucode.h. This header gets included in main.c and uploaded to VRAM (starting at memory locations 0x1900) by the host program. If you want to see the assembled code, the simplest thing you can do is use js99er's debugger to look at VRAM from 0x1900 and onwards (roughly 300 bytes, I think). As I said, both versions upload the code to 0x1900 in VRAM, but in the broken version the entrypoint of the 'main' function is at 0x1948 (so GPU execution starts there instead of at 0x1900), with the first 0x48 bytes occupied by code that gets jumped to later (functions in C). The working version just starts at 0x1900, since there the functions are inlined.
  8. Yeah, it's not going to run on Classic99, that's normal. But indeed, I just tested on my real hardware and it crashes there as well. The strange thing is that it runs fine in js99er.net and it is damn hard to debug on RI *edit* The version attached to this post does run on the real deal (and it runs quite a bit faster, making the effect more convincing). I only inlined some functions in the GPU program, which probably means that my tools to compile C code for the GPU don't always work when using regular function calls. (I left the original up as well, if Rasmus wants to verify why js99er gave different results to the real HW) Video proof: https://www.youtube.com/watch?v=RY_8i_ouXc8 fire.dsk
  9. I thought I'd take a stab doing a fire demo effect on the f18a, more details here: http://atariage.com/forums/topic/207586-f18a-programming-info-and-resources/?p=3277853
  10. Ok, cool, thanks. Well, inspired by sometimes99er's fire demo, I did one for the f18a. The cool thing about the f18a is that it makes all those old DOS effects new again, so I dug out an old fire demo I did and ported it to the F18A. The result is attached, and here's a video for the f18a impaired (or lazy people): https://www.youtube.com/watch?v=k2Qg-QqnJVM This isn't optimized, and there is some "black snow" because I'm not double buffering, but I think it looks nice enough... Not tested on real iron yet, and NOT reset button safe fire-src.tar.gz fire.dsk
  11. Sorry for spamming the thread with all my questions, but is the 16-color fat pixel BML mode documented somewhere? My assumption is that the destination operand's lower nibble will define the color of a fat pixel, and that e.g. the following command would plot a pixel with color 14 at location (32,32) in the BML: LI r0,>2020 LI r1,>000e PIX r0,r1 That's not what I'm seeing however, but I might be doing something wrong...
  12. Is the RNG at >9000 still available from GPU programs? If so, is it implemented in js99er? *edit* Nevermind... just re-read the changelog, it's clearly there that it is removed.
  13. Great news, thanks! Regarding libgcc: I just tried rebuilding the entire thing from scratch, and libgcc did build as expected this time. I must have been playing around with a dirty build before. My apologies for sending you on a wild goose chase... Regarding new features, it would be great if the compiler could 'natively' support paged/banked memory configurations (like an AMS or 512k cart type setup). Not sure if this is a compiler feature though, it might be something that is best achieved with a separate set of tools?
  14. Not divide by zero, that would be a runtime error. The error I get is at compilation time, where divide by zero cannot be verified yet.
  15. Turn out, I also have the latest version of the compiler on my laptop, and hotels are boring at night . Anyway, this is the minimum code needed to trigger the error: /*************************/ /* TI-99/4A Ray caster */ /* 2013 - Danny Lousberg */ /*************************/ // Includes #include "lookup.h" // Needed to calculate movement // Defines #define MAX_INT 32767 #define MAP_WIDTH 24 #define MAP_HEIGHT 24 #define CELL_SIZE 32 // Size of each wall "cube" on the map: width, depth and height #define SCREEN_WIDTH 64 // Number of rays to cast, or number of columns, or slices #define SCREEN_HEIGHT 64 // Height of the rendering surface, in pseudo-pixels; not including bottom area #define FOV 64 // Field Of View, aka how wide the arc of rays needs to be #define SCREEN_DISTANCE 3200 // Distance to screen projection plane // Formula for this is (SCREEN_WIDTH / 2) / tan(FOV / 2) #define ANGLE_STEP 1 // Should be FOV / SCREEN_WIDTH, so FOV needs // to be a multiple of SCREEN_WIDTH, effectively // giving a max resolution of 64 for // realistic looking rendering #define SLICEPARAMBUFFER 0x2000 // Where in VRAM do we put our slice parameters? 4 bytes in a row at 0x2000 (8k) #define ABS(a) (((a) < 0) ? -(a) : (a)) // World map char worldmap[MAP_WIDTH][MAP_HEIGHT] = { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,2,2,0,2,2,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1}, {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1}, {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,2,2,0,2,2,1,0,0,0,3,0,3,0,3,0,0,0,1}, {1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1}, {1,1,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,2,2,2,2,2,2,2,2,2}, {1,0,0,0,0,1,0,0,0,0,0,1,2,2,2,2,0,0,0,0,0,0,0,2}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}, {1,0,0,0,0,0,0,0,0,0,0,1,2,2,2,2,0,0,0,0,0,0,0,2}, {1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,2,0,0,0,0,0,0,0,2}, {1,2,2,2,0,0,0,0,2,0,0,0,0,0,0,2,2,2,2,0,2,2,2,2}, {1,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1}, {1,2,0,2,0,0,0,0,2,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1}, {1,2,0,2,2,2,2,2,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1}, {1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,2,2,2,2,2,2,2,2,0,0,0,0,0,0,1,0,0,1,1,1,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} }; //********************* // VDP access ports //********************* // Write Address/Register #define VDPWA *((volatile unsigned char*)0x8C02) // Write Data #define VDPWD *((volatile unsigned char*)0x8C00) //********************* // Inline VDP helpers //********************* // Set VDP address for write (adds 0x4000 bit) inline void VDP_SET_ADDRESS_WRITE(unsigned int x) { VDPWA=((x)&0xff); VDPWA=(((x)>>|0x40); } // Set VDP write-only register 'r' to value 'v' inline void VDP_SET_REGISTER(unsigned char r, unsigned char v) { VDPWA=(v); VDPWA=(0x80|(r)); } void draw_slice(unsigned char column, int slicestart, int sliceend, unsigned char color) { // Write parameters to VRAM VDP_SET_ADDRESS_WRITE(SLICEPARAMBUFFER); VDPWD = (unsigned char)column; VDPWD = (unsigned char)slicestart; VDPWD = (unsigned char)sliceend; VDPWD = (unsigned char)color; // Kick of slice rendering program VDP_SET_REGISTER(54, 0x20); VDP_SET_REGISTER(55, 0x04); } // The actual ray casting algorithm, called once per frame // Basically, we iterate over each screen column and calculate the angle of view // that is associated with that column. Then we "cast a ray" from the player's position // along that angle until we hit a wall in our map. // We use the distance to that wall to calculate the height of the slice to be // rendered for the current column (the further away, the smaller the slice) void cast_rays(int playerx, int playery, int playerangle) { int column; // column iterator, range: 0-SCREEN_WIDTH int rayangle; unsigned int hordist, verdist; // distance to the closest wall in horizontal _and_ vertical direction int mapx, mapy; // temp values for checking a hit on the map, will be copied into hitx,hit int hitx, hity; // coords in map space of the _closest_ hit (either vert or hort) unsigned int distance; // distance of the _closest_ hit (either vert or hort) int xstep, ystep; // How many units to step from one wall-boundary to the next int checkx, checky; // coords of the first intersection, before we start "stepping" int side = 0; // First ray, left-most column starts at half the FOV counterclockwise from the player's angle rayangle = playerangle - FOV / 2; hitx = hity = 0; for(column = 0; column < SCREEN_WIDTH; column++) { // Normalize angle to 0-359 range if (rayangle < 0) rayangle += 360; if (rayangle >= 360) rayangle -= 360; // Initialize distance, will be used in comparison later on // and there is a code path that could leave this undefined distance = MAX_INT; // Check for horizontal intersections if ((rayangle != 0) && (rayangle != 180)) { int hit; // Boolean to stop checking for walls // initialize to longest distance as we will be picking the shortest distance // to a hit between the two axis hordist = MAX_INT; // Calculate first intersection point on next cell along ray // First we calculate the Y coord (easiest) if (rayangle > 180) { // ray is facing up in the map; so we put the checkpoint RIGHT ABOVE (hence the - 1) // the boundary of the cell we are in on the Y-axis checky = ((playery / CELL_SIZE) * CELL_SIZE) - 1; xstep = -STEPX[rayangle]; // = (256 * -CELL_SIZE) / TAN255[rayangle]; ystep = -CELL_SIZE; } else { // ray is facing down in the map; so we put the checkpoint right AT // the boundary of the cell BELOW the one we are in on the Y-axis checky = ((playery / CELL_SIZE) * CELL_SIZE) + CELL_SIZE; xstep = STEPX[rayangle]; // = (256 * CELL_SIZE) / TAN255[rayangle]; ystep = CELL_SIZE; } checkx = playerx - ( (256 * (playery - checky)) / TAN255[rayangle] ); hit = 0; mapx = checkx / CELL_SIZE; mapy = checky / CELL_SIZE; while (!hit) { // Ray has left the map; need to break out of the loop if ( (mapx < 0) || (mapy < 0) || (mapx >= MAP_WIDTH) || (mapy >= MAP_HEIGHT) ) { hordist = MAX_INT; break; } // if we hit a non-zero field in the map, we're on the edge of a wall if (worldmap[mapx][mapy]) { hit = 1; hordist = 1; } else { // No wall? Then we take steps to the next boundary and // reset the map coords to be checked checkx += xstep; checky += ystep; mapx = checkx / CELL_SIZE; mapy = checky / CELL_SIZE; } } // Only checked horizontal hits yet, so these are by definition our best guess for // the closest hit. We'll check these values against the vertical results later on // so we store in the variables for the final result for now... hitx = mapx; hity = mapy; distance = hordist; } else { // Angles 0 and 180 have a cos of zero // or in other words, we will never see a horizontal intersection hordist = MAX_INT; } // Check for vertical intersections if ((rayangle != 90) && (rayangle != 270)) { int hit; // Boolean to stop checking for walls // initialize to longest distance as we will be picking the shortest distance // to a hit between the two axis verdist = MAX_INT; // Calculate first intersection point on next cell along ray // First we calculate the X coord (easiest) if ( (rayangle < 270) && (rayangle >= 90) ) { // Going left, check against left boundary of current cell checkx = ((playerx / CELL_SIZE) * CELL_SIZE) - 1; ystep = -STEPY[rayangle]; // = (-CELL_SIZE * TAN255[rayangle]) / 256; xstep = -CELL_SIZE; } else { // facing right, check against LEFT boundary of NEXT cell checkx = ((playerx / CELL_SIZE) * CELL_SIZE) + CELL_SIZE; ystep = STEPY[rayangle]; // = (CELL_SIZE * TAN255[rayangle]) / 256; xstep = CELL_SIZE; } // The below should simply be "checky = playery - ( ((playerx - checkx) * TAN255[rayangle]) >> 8 );" // But this result overflows when angles approach 90 or 270, likelyhood increase the bigger // the distance between test point and player gets // So, for high result values of TAN255, we just pre-scale the numbers before the multiplication // For the lower numbers, we don't do prescale since we'de lose too much precision if ( ABS(TAN255[rayangle]) > 1000 ) checky = playery - ( ((playerx - checkx) * (TAN255[rayangle] >> 4)) >> 4 ); else checky = playery - ( ((playerx - checkx) * TAN255[rayangle]) >> 8 ); hit = 0; mapx = checkx / CELL_SIZE; mapy = checky / CELL_SIZE; while (!hit) { // Ray has left the map; need to break out of the loop if ( (mapx < 0) || (mapy <0) || (mapx >= MAP_WIDTH) || (mapy >= MAP_HEIGHT) ) { verdist = MAX_INT; break; } // if we hit a non-zero field in the map, we're on the edge of a wall if (worldmap[mapx][mapy]) { hit = 1; verdist = 1; } else { // No wall? Then we take steps to the next boundary and // reset the map coords to be checked checkx += xstep; checky += ystep; mapx = checkx / CELL_SIZE; mapy = checky / CELL_SIZE; } } } else { // cos of 90 and 270 is zero, so there is never an intersection with a vertical wall verdist = MAX_INT; } // See which of our hits we should take into account // Default was horizontal, but we take vertical if that distance is shorter side = 0; if (verdist <= hordist) { hitx = mapx; hity = mapy; distance = verdist; side = 1; } // calculate slice height based on distance int sliceheight, slicestart, sliceend; if (distance) sliceheight = SCREEN_DISTANCE / distance; else sliceheight = SCREEN_HEIGHT; slicestart = (SCREEN_HEIGHT - sliceheight) / 2; sliceend = slicestart + sliceheight; // Start of rendering this slice // Color of wall slice char color; if (side != 1) { // Front view, light colors switch(worldmap[hitx][hity]) { case 1: color = 15; break; // white case 2: color = 2; break; // green case 3: color = 5; break; // blue default: color = 11; break; // yellow } } else { // Side view, dark colors switch(worldmap[hitx][hity]) { case 1: color = 14; break; // gray case 2: color = 12; break; // dark green case 3: color = 4; break; // dark blue default: color = 10; break; // dark yellow } } // draw the pixels of the stripe as a vertical line draw_slice(column, slicestart, sliceend, color); // Prepare for next column rayangle += ANGLE_STEP; } } int main(int argc, char *argv[]) { while(1) { } return 0; } Note that this code doesn't perform anything useful anymore, and I took some of the calculations out, so the algorithm itself won't work either. Don't know how significant this is, but I found it strange that although the error during compilation is reported in line 278, commenting out line 312 will actually make it go away... Attached is a folder containing all that's needed to build this (and trigger the bug). Again, for others that would be tempted to download this: it does not contain a working program... wolfie-error.tar.gz
  16. Plastik, I just want to say that I like the graphics you create. Shame the Mario stuff isn't technically possible on the real hardware, but even the simplified stuff is really well done. Kudos.
  17. I'm currently traveling for work, but I'll prepare a file for you ASAP, probably second half of the week. I'm more than happy to help debug this. Just let me know where to look, and what you want me to do. I think the reason libgcc won't build could be the same reason why my own code won't build. I'll dig up the exact error when I'm near my main computer later this week, but given libgcc implements a number of math functions it wouldn't surprise me the error is the same here.
  18. I had an Asus motherboard that did that 10 years ago or so. It basically "talked" through the POST routine. Annoying as hell after a while, but it was a neat (LAN-)party trick.
  19. I get why you would say that, but to me there's a world of difference between emulators and FPGA implementations. Different strokes for different folks, right... I'm not a purist by any means, but there's surely gradations for me: "Classic" Real Iron > Mixed setup with newer components (e.g. F18A, Lotharek, NanoPeb) > Full-on FPGA implementation ala MIST > Emulation
  20. Thanks Insomnia. Actually, I get another error when trying your test: Dannys-MacBook-Pro:wolfie-f18a lousbergd$ echo "int test() { return 1; }" > test.c Dannys-MacBook-Pro:wolfie-f18a lousbergd$ /Users/lousbergd/tms9900/bin/tms9900-gcc -da test.c /Users/lousbergd/tms9900/bin/../lib/gcc/tms9900/4.4.0/../../../../tms9900/bin/ld: cannot find -lgcc Dannys-MacBook-Pro:wolfie-f18a lousbergd$ ls *_subreg test.c.171r.tms9900_subreg So, it does look like I'm using the latest version, but it seems that something else is going wrong. I'm not on my home PC now, so I can't give you the install script I modified, but it was extremely simple (basically a find and replace of "wget" with "curl -O"). I'll make a patch for my changes to toplev.c and toplev.h and include the application of that patch in the script if it detects it's running on a Mac.
  21. Keep in mind that not all 512k carts will ship software that requires the 32k expansion, most (if not all) of the collections currently available do, but that's a function of the software installed on the carts, not the hardware itself.
  22. Thanks for the update Insomnia! However, I'm not sure I'm using the last version. I used (and modified) the install script from the first post, the patch file says 1.11 (and 1.7 for binutils), but I get the same problems as with the last version: Build of libgcc crashes (removed that from build script) Errors during compilation when converting bytes-ints Errors with certain divisions. I'm wondering if there's a way to verify the patch level from a compiled binary? It's not part of the version number, which just reports 4.4.0 . These are the error messages I get: wolfie3.c: In function ‘cast_rays’: wolfie3.c:403: internal compiler error: in subreg_highpart_offset, at emit-rtl.c:1304 for this code (SCREEN_DISTANCE is a '#define 3200', distance is an unsigned int) // calculate slice height based on distance int sliceheight, slicestart, sliceend; if (distance) sliceheight = SCREEN_DISTANCE / distance; else sliceheight = SCREEN_HEIGHT; And: /Users/lousbergd/tms9900/bin/tms9900-ld crt0_ea5.o utils.o tistdio.o wolfie3.o --section-start .text=0xa000 --section-start .data=0x2080 -M -L./libti99 -lti99 -o wolf18a.ea5.elf > ea5.map wolfie3.o: In function `L55': (.text+0x1ce): undefined reference to `__divsi3' For the expression in this code: verdist = (int)( (long)(256 * ABS(checkx - playerx)) / (long)(ABS(COS255[rayangle])) ); I think the __divsi3 stuff might be related to libgcc not being built, and the first error is probably a type conversion error, but if I understand it correctly both of these should be fixed, right? Not related, but for people trying to compile this on a Mac - and as a reminder for myself next time I want to compile this: note that you need to do a couple of things to make everything compile correctly: Modify the install script by replacing every instance of 'wget' with 'curl -O', since there's no wget on OS X anymore You will need to modify toplev.c and toplev.h to fix a host compiler version check that fails with clang (the floor_log2 and exact_log2 functions will redefine an inline function, which isn't allowed in c99, but gcc will allow this). Just remove the inline version in toplev.h and the test around the implementation in toplev.c. (for now, I think...) remove libgcc from the targets in the gcc config line in install.sh Either way, a big thank you for all your efforts, I wouldn't be coding for the TI again if it wasn't for this!
  23. The SGCPU board is a great example of what would be possible if we did this again today. The problem with it for me is that it's a PEB-only solution, I would love a new motherboard for the console that has extra memory on board (SAMS compatible preferably) but still maintains all of the TI's interfaces (side port, cartridge slot, casette port, joysticks, ...). Just something than can be populated with existing components where possible, and modern replacements where original chips are becoming hard/impossible to find (e.g. GROM chips), or for those looking for upgraded functionality (e.g. F18A). In terms of nostalgia, I generally tend to think of things "that were possible" back in the day as meeting that criterion. I wouldn't care of we used a single-chip SRAM approach instead of 24 separate chips in a new version of the SAMS, and I don't mind the F18A using an FPGA since it really doesn't do anything that was technically impossible back in the 80's.
  24. I figured as much. I'm already counting on the ability to reduce the stride between bitplanes to make the sprite pattern table fit in 3k instead of the normal 6k. 64 patterns per player are enough to display the on-screen sprites, but I also need to find room to put a backbuffer somewhere in memory for the next animation frame while it's being uploaded from the host system. Unless there's a way to optimize VRAM usage that I haven't figured out yet, I think a streetfighter game would need to be restricted to one plane only.
  25. Seconded. Although instead of being able to upgrade it, simply shipping the damn computer with some would've been awesome...
×
×
  • Create New...