-
Content Count
3,713 -
Joined
-
Last visited
-
Days Won
7
Content Type
Profiles
Member Map
Forums
Blogs
Gallery
Calendar
Store
Everything posted by intvnut
-
Answering my own question by looking at the code in MAME. void tms99xx_device::alu_abs() { // LAECO (from original word!) // O if >8000 // C is alwas reset set_status_bit(ST_OV, m_current_value == 0x8000); set_status_bit(ST_C, false); compare_and_set_lae(m_current_value, 0); if ((m_current_value & 0x8000)!=0) { m_current_value = (((~m_current_value) & 0x0000ffff) + 1) & 0xffff; pulse_clock(2); // If ABS is performed it takes one machine cycle more } else { MPC++; // skips over the next micro operation (MEMORY_WRITE) } pulse_clock(2); } It appears Carry isn't set usefully. But, it appears the other flags are set based on the original value, not the value after negation. So, you could shave a couple cycles with: ABS R0 ; 12 + 2*mem (if positive) JEQ DONE ; 8 + 1*mem (n/t) SETO R0 ; 10 + 3*mem JLT DONE ; 8 + 1*mem (n/t) INCT R0 ; 10 + 3*mem DONE ... ;------------ ; 48 + 10*mem I guess I had missed the fine print "If MSB(SA) = 0 and (SA) ≠ 0" here:
-
*doh* Of course! You can use the fact R0 is 0 to save an instruction over my approach, and be slightly faster both on average and in the worst case. MOV R0,R0 ; 14 + 4*mem JEQ DONE ; 8 + 1*mem (n/t) SETO R0 ; 10 + 3*mem JLT DONE ; 8 + 1*mem (n/t) INCT R0 ; 10 + 3*mem DONE ... ;------------ ; 50 + 12*mem 50+12*mem is noticeably faster than my 58+14*mem. It's annoying MOV is 14 + 4*mem. Does ABS set Carry in a useful way for positive vs. negative numbers? It's faster than MOV for positive numbers, and uses fewer memory cycles in all cases.
-
Don't you need to move R0 to R1 after the SRA? The SRA will take 2 cycles for every position shifted, plus 12 cycles, plus 3 mem cycles. That makes it pretty expensive. (42 + 3*mem). If I add up the worst case for your routine (adding the missing MOV): LI R1, 1 ; 12 + 3*mem MOV R0, R0 ; 14 + 4*mem JGT DONE ; 8 + 1*mem (not taken) SRA R0, 15 ; 42 + 3*mem MOV R0, R1 ; 14 + 4*mem DONE ... ;------------ ; 90 + 15*mem How about this one, which leaves the result in the same register it started with? NEG R0 ; 12 + 3*mem Sets EQ if zero, GT if negative SETO R0 ; 10 + 3*mem R0 = -1, no flag modifications JGT DONE ; 8 + 1*mem (n/t) If R0 was negative, we're done. JNE POS ; 8 + 1*mem (n/t) If R0 was non-zero, turn -1 to +1 DEC R0 ; 10 + 3*mem R0 was 0, so turn -1 to -2, to become 0 POS: INCT R0 ; 10 + 3*mem This either gives is 0 or +1 now. DONE: ;----------- ; 58 + 14*mem I think this ends up being the same size, too, once you add the missing MOV to yours. (FWIW, I'm using the cycle counts here, and the instruction references here and here.) I know the original request was without tests or jumps: But on this architecture, jumps are surprisingly cheap compared to the alternatives. They're cheaper than MOVs, which is surprising until you remember this is a memory-memory architecture.
-
On LTO Flash: I'm working through all of my project backlog right now, and will eventually get to programming those boards. I have two boxes full of LTO Flash boards in my livingroom waiting for some love. They're a bit more complicated to program and test than JLP boards, and I have a number of requests for JLP boards as well. I also need to bust out my plastic notching tool. I'm not going to give a target date until I have something ready to ship. As for the bus phases that Yarok quoted above: I need to point out (as I did in email) that you also need the ADAR bus phase. I'll quote my email here for everyone's benefit.
-
The backslash needs to be the absolute last character on the line. This red dot hints you have a space character causing trouble.
-
You might also want to load #backtab(#pos_joueur) into a temporary variable, as it appears IntyBASIC (at least v1.4.1) doesn't re-use the value it loaded. #tmp = #backtab(#pos_joueur) IF (#tmp = ECHELLE1) \ + (#tmp = ECHELLE2) \ + (#tmp = ECHELLE3) \ + (#tmp = ECHELLE4) \ + (#tmp = ECHELLE5) \ + (#tmp = ECHELLE6) THEN ' ... stuff ... END IF Assuming ECHELLE1 through ECHELLE6 are constants, there may be even better ways to write this depending on what the values are. I did try writing up a generic "FIND" assembly helper. Counting the cycles, it's about the same as using a temp variable in the worst case (value not found), and shows bigger wins when the value is found in the list: ' Call this as USR Find(VARPTR table(0), length, value) ' Returns 1 through N if found, or 0 if not. ASM FIND: PROC ASM MOVR R0, R4 ASM @@1: [email protected] R4, R2 ASM BEQ @@2 ASM DECR R1 ASM BNEQ @@1 ASM MOVR R0, R4 ASM @@2: SUBR R0, R4 ASM MOVR R4, R0 ASM JR R5 ASM ENDP ' Usage example: IF USR Find(VARPTR items(0), 6, #backtab(#pos_joueur)) > 0 THEN ' ... stuff ... END IF ' Elsewhere, outside a Procedure: items: DATA ECHELLE1, ECHELLE2, ECHELLE3 DATA ECHELLE4, ECHELLE5, ECHELLE6 With that kind of helper, you could also start to use ON Find(...) GOTO or ON Find(...) GOSUB to do even fancier things.
-
Freewheeling Games - free ROM downloads
intvnut replied to freewheel's topic in Intellivision / Aquarius
I'm going to have to try Desert Bus with --macho. Running jzIntv with --macho=N, where N is a number, multiplies the game speed by N. --macho=1.5 is 50% faster, --macho=2 is 100% faster (twice as fast), etc. With --macho=8, one way should take an hour. -
I forgot one other detail: The divide routine returns 0 if you divide by 0. Since the code divides population by 100, rounding toward 0, this gives you a 0 divisor for a bunch of the calculations. Dividing by 0 population zeroes out those scores. That fleshes out the rest of the explanation.
-
OK, I believe -100 and below should give you "max 100". Here's my reasoning: Population is stored as a 16-bit value. When computing the score, the code performs a non-rounding divide by 100: L_5ABD: MVII #POPU_0,R4 ; 5ABD \ JSR R5, L_5A29 ; 5ABF |_ Get player's (updated) SDBD ; 5AC2 | population count [email protected] R4, R1 ; 5AC3 / MVII #$0064, R2 ; 5AC4 \_ Pop / 100 JSR R5, X_DIV ; 5AC6 / I checked the divide code, and it appears to correctly account for the signs of both numerator and denominator. It remembers the sign of the numerator and denominator, flips them both positive, and then sets the sign of the result to the XOR of the two signs (effectively). So +/+ gives +, -/- gives +, and +/- or -/+ gives -. So, the divide above will clamp populations from -99 to 99 down to 0 for scoring, fitting your -100 < X < 100 criterion. For -100 and below, the computation above results in a negative value. The subsequent subscore computations use this negative value and compute negative scores. For example, this computes a negative housing score: MVII #HOUS_0,R1 ; 5ACB \ ADD CURPLR, R1 ; 5ACD |- Get number of houses [email protected] R1, R0 ; 5ACF / MVII #$01F4, R1 ; 5AD0 \_ Houses * 500 JSR R5, X_MPY ; 5AD2 / MOVR R2, R1 ; 5AD5 \ MVI G_0324, R2 ; 5AD6 |- (Houses * 500) / (pop / 100) JSR R5, X_DIVR ; 5AD8 / rounded MOVR R0, R1 ; 5ADB \ MVII #$0003, R2 ; 5ADC |- ((Houses*500)/(pop/100)) / 3 JSR R5, X_DIVR ; 5ADE / rounded CMPI #$001E, R0 ; 5AE1 \ BLE L_5AE7 ; 5AE3 |- Clamp housing score at 30 MVII #$001E, R0 ; 5AE5 / So what happens next? L_5AE7: MVO R0, H_SCOR ; 5AE7 Remember housing score That looks pretty innocuous, until you realize H_SCOR is in 8-bit memory. That negative score now looks like a large positive 8-bit value. This pattern repeats for the other subscores. MVII #RGLD_0,R4 ; 5AE9 \ ADD CURPLR, R4 ; 5AEB |- Get gold earned this round [email protected] R4, R0 ; 5AED / This is total GDP for round MVII #$0064, R1 ; 5AEE \_ Multiply by 100 JSR R5, X_MPY ; 5AF0 / MOVR R2, R1 ; 5AF3 \ Compute per capita GDP as MVI G_0324, R2 ; 5AF4 |- (gold * 100) / (pop / 100) JSR R5, X_DIVR ; 5AF6 / rounded MOVR R0, R1 ; 5AF9 \ Per capita GDP score is MVII #$000C, R2 ; 5AFA |- ((gold*100) / (pop/100)) / 12 JSR R5, X_DIVR ; 5AFC / rounded CMPI #$001E, R0 ; 5AFF \ BLE L_5B05 ; 5B01 |- Clamp GDP score at 30 MVII #$001E, R0 ; 5B03 / L_5B05: MVO R0, G_SCOR ; 5B05 Remember per capita GDP score G_SCOR is also in 8-bit memory. This will also look like a large positive 8-bit value. ;; Compute food-supply score ;; Note: This can overflow if (crops + fishing boats) > 65 MVII #F_BO_0,R1 ; 5B07 \ ADD CURPLR, R1 ; 5B09 |- Get number of fishing boats [email protected] R1, R0 ; 5B0B / MVII #CROP_0,R2 ; 5B0C \ ADD CURPLR, R2 ; 5B0E |_ Add number of crops [email protected] R2, R1 ; 5B10 | ADDR R0, R1 ; 5B11 / MVII #$01F4, R0 ; 5B12 \_ (boats + crops) * 500 JSR R5, X_MPY ; 5B14 / > Can go "negative" if more ; > than 65 fishing boats + crops MOVR R2, R1 ; 5B17 \ MVI G_0324, R2 ; 5B18 |- (boat+crops)*500 / (pop/100) JSR R5, X_DIVR ; 5B1A / MOVR R0, R1 ; 5B1D \ Food supply score: MVII #$0003, R2 ; 5B1E |- ((boat+crops)*500/(pop/100))/3 JSR R5, X_DIVR ; 5B20 / CMPI #$001E, R0 ; 5B23 \ BLE L_5B29 ; 5B25 |- Clamp at 30 MVII #$001E, R0 ; 5B27 / L_5B29: MVO R0, F_SCOR ; 5B29 Remember food score Ditto F_SCOR. Finally, they all get added together with the general welfare score as 16-bit arithmetic, and clamped to 100. Because the negative values above got whitewashed into looking like positive values, this sum is way larger than 100 but positive: CLRR R1 ; 5B2B \ Base round score: ADD H_SCOR, R1 ; 5B2C |_ housing + GDP + food ADD G_SCOR, R1 ; 5B2E | ADD F_SCOR, R1 ; 5B30 / ;; General welfare scoring: MVII #SCHL_0,R2 ; 5B32 \ ADD CURPLR, R2 ; 5B34 |_ Add 1 point for every school [email protected] R2, R0 ; 5B36 | ADDR R0, R1 ; 5B37 / MVII #HOSP_0,R2 ; 5B38 \ ADD CURPLR, R2 ; 5B3A |_ Add 1 point for every hospital [email protected] R2, R0 ; 5B3C | ADDR R0, R1 ; 5B3D / CMPI #$0064, R1 ; 5B3E \ BLE L_5B44 ; 5B40 |- Clamp round score at 100 MVII #$0064, R1 ; 5B42 / Mystery explained?
-
I will definitely have to review my disassembly and make corrections. I'm not sure I followed this calculation: Where did the 1.1% come from? EDIT: Never mind: Baseline mortality.
-
OK, I looked at the code, and I apparently must have made a gigantic brain fart in the wee hours of the morning when I said there was a lower bound of 4% on the fertility. CMPI #$0040, R3 ; 5A6C \ BLE L_5A72 ; 5A6E |- Min fertility of 40. MVII #$0040, R3 ; 5A70 / L_5A72: MVI G_0324, R0 ; 5A72 Get pop/10 That comment is 100% bogus. Here's what it should say: CMPI #$0040, R3 ; 5A6C \ BLE L_5A72 ; 5A6E |- Max fertility of 64. MVII #$0040, R3 ; 5A70 / L_5A72: MVI G_0324, R0 ; 5A72 Get pop/10 That's right, it's a clamp on the upper bound of fertility, not the lower bound. *d'oh* 24 schools should be a -7.2% on bias on fertility. 4.0% - 7.2% = -3.2%. 5 factories should be 1.1% + 5 * 0.1% = 1.6% mortality. So, for a population of 1000, you should see 1000 - 3.2% *1000 - 1.6% * 1000 = 1000 - 32 - 16 = 952. A -4.6% would take 1000 down to 954. Can you double check your measurements? As for negative population driving 100 scores, I can see that. I need to investigate what the divide routine does when passed a negative divisor and/or dividend. It's possible one or more steps treat the negative number as a large positive number, giving an off-the-charts score. There are three score components that involve population, and those only add to 90. You'd need to get the other 10 points through schools or hospitals (general welfare score).
-
Hmm. Let me go take a look at the source. I probably made some errors. For example: MVII #$0028, R3 ; 5A40 Fertility baseline of 50 (5.0%) $28 is 40, not 50. So... clearly I need to review this.
-
I don't know how you have the controller interfaced to your computer. Can you run event_diag.rom (comes w/ jzIntv) and see what events get signaled to jzIntv for each of those inputs?
-
That's due to an incompatibility between Ms. Pac-Man and the ECS that LTO Flash cannot work around. If you put Ms. Pac-Man on a dedicated cartridge, you'd see the same thing. Ms. Pac-Man writes to GRAM aliases at $7xxx, $Bxxx, and $Fxxx, but the ECS actively blocks that. LTO Flash is able to work around the more common sources of ECS incompatibility due to conflicts with the ECS ROMs. At the time I designed LTO Flash, I was not aware of this particular flavor of incompatibility.
-
Config files to use with various Intellivision titles
intvnut replied to intvnut's topic in Intellivision / Aquarius
In my experience, .INT files are usually (but not always!) equivalent to .BIN files. -
I've thought about doing it. You could either do FPGA or maybe a microcontroller. Microcontroller is a bit trickier because you'd likely need to write very carefully threaded code. It'd be rather close to what it's like to code on the Atari2600, I'd imagine. ie. Set up a DMA engine to DMA a line buffer to the GPIO at a particular rate for the "pixel out", while the MCU has to balance time between MCU bus cycles and rendering to the line buffer. I'd tackle it, but I've got too many higher priority things ahead of that.
-
It can cause problems. Read accesses to location $8021 can flip the display mode when you're not expecting it, for example. If you want to use JLP mode, those addresses overlap its RAM as well (starting at $8040).
-
Technically speaking, the "INTV Corp" title screen is a function of the INTV 1986 GROM, and not whether you have the TutorVision WBEXEC. The message exists in the GROM chip, and so all INTV88 boards will have that modified message regardless of whether the WBEXEC is present.
-
inty basic problem: stupid spaces
intvnut replied to atari2600land's topic in Intellivision Programming
I suppose you could even make that almost readable with a couple macros like so: DEF FN backtab_tile(color, tile) = color + (tile) * 8 DEF FN backtab_char(color, char) = color + (char - $20) * 8 #backtab(154) = backtab_tile($1202, 319) #backtab(155) = backtab_char($1202, "2") #backtab(157) = backtab_char($1202, "2") #backtab(156) = backtab_char($1202, "0") #backtab(158) = backtab_char($1202, "0") -
inty basic problem: stupid spaces
intvnut replied to atari2600land's topic in Intellivision Programming
That's smaller in size, but I am pretty sure it's not faster speed-wise. And, of course, there's packed character strings if you have a lot of text to deal with. The GROM is mostly ASCII shifted down my $20, so it's somewhat ASCII compatible, much like PETSCII. If you really want the smallest, fastest code, you probably end up with something like this: #backtab(154) = $1202 + 319*8 #backtab(155) = $1202 + 18*8 #backtab(157) = $1202 + 18*8 #backtab(156) = $1202 + 16*8 #backtab(158) = $1202 + 16*8 Notice the ordering. IntyBASIC takes advantage of the repeated value: MVII #7162,R0 MVO R0,Q2+154 MVII #4754,R0 MVO R0,Q2+155 MVO R0,Q2+157 MVII #4738,R0 MVO R0,Q2+156 MVO R0,Q2+158 -
inty basic problem: stupid spaces
intvnut replied to atari2600land's topic in Intellivision Programming
Strangely, that results in more expensive code in IntyBASIC 1.4.1, as it saves and reloads the _screen pointer unnecessarily, and has to separately XOR in _color. My way: ;[3] #backtab(154) = $1202 + 319*8 SRCFILE "copr.bas",3 MVII #7162,R0 MVO R0,Q2+154 ;[4] print at 155 color $1202, "2020" SRCFILE "copr.bas",4 MVII #667,R0 MVO R0,_screen MVII #4610,R0 MVO R0,_color MVI _screen,R4 MVII #144,R0 XOR _color,R0 [email protected] R0,R4 XORI #16,R0 [email protected] R0,R4 XORI #16,R0 [email protected] R0,R4 XORI #16,R0 [email protected] R0,R4 MVO R4,_screen Your way: SRCFILE "copr.bas",5 ;[6] PRINT AT 154 COLOR $1202,"\319","2020" SRCFILE "copr.bas",6 MVII #666,R0 MVO R0,_screen MVII #4610,R0 MVO R0,_color MVI _screen,R4 MVII #2552,R0 XOR _color,R0 [email protected] R0,R4 MVO R4,_screen MVI _screen,R4 MVII #144,R0 XOR _color,R0 [email protected] R0,R4 XORI #16,R0 [email protected] R0,R4 XORI #16,R0 [email protected] R0,R4 XORI #16,R0 [email protected] R0,R4 MVO R4,_screen Your way is definitely cleaner, though. I suppose this is yet another opportunity for nanochess to optimize. -
inty basic problem: stupid spaces
intvnut replied to atari2600land's topic in Intellivision Programming
Did you mean as a GRAM tile, not MOB? (MOB = Sprite) In any case, it feels like IntyBASIC should stop parsing the \ escape after 3 digits, but trying it just now, it appears it doesn't. In the meantime, you could just do: #backtab(154) = $1202 + 319*8 print at 155 color $1202, "2020" -
Whoo hoo! I eyeballed it correctly. Very nice. It seemed like the POP macros were unneeded overhead. They make the code easier to follow, but direct SP manipulation seems more efficient (space, and hopefully time).
