ToroCraft / Minecoprocessors

Increase your redstone possibilities and learn assembly programming at the same time with the Minecoprocessors Minecraft Mod!
https://minecraft.curseforge.com/projects/minecoprocessors
GNU General Public License v3.0
33 stars 10 forks source link

Submission for example programs: Falling Edge Detector #66

Open Zexks opened 3 years ago

Zexks commented 3 years ago

mov ports, 0010b start: cmp pb, 0 jz start wait: cmp pb, 0 jnz wait mov pf, 1b mov c, 5 loop: dec c jnz loop mov pf, 0 jmp start

Used this for several machines that require crafting mods to do a single craft at a time. AE2 has a setting called blocking mode but other mods require redstone signals between crafts.

Still seems to have issues with recognizing '1' in the cmp command. tried with 0xff but couldn't get that to work either. Had to go off 0 checks.

stfwi commented 3 years ago

@frodare Hi, I just stumbled over this, should the GPIO read 0xf or 0x1? If ladder I could quickly make the change. Cheers.

frodare commented 3 years ago

@stfwi It has been long enough since I built this mod that I am not sure. I think I wanted to represent 1 as 0x1, but at some point it was outputting 0xf.

paperky commented 3 years ago
//code

Used this for several machines that require crafting mods to do a single craft at a time. AE2 has a setting called blocking mode but other mods require redstone signals between crafts.

Still seems to have issues with recognizing '1' in the cmp command. tried with 0xff but couldn't get that to work either. Had to go off 0 checks.

@Zexks It seems that the ports in Digital mode read out as either 0x00 or 0xFF. In ADC mode, they read from 0x0 to 0xF. You have a few options to read "if port is High" (if any redstone signal at back): Have pb in ADC mode, and use cmp pb, 0x01 with jge to jump if high OR Have pb in digital mode, and use cmp pb, 0xFF with jz/je to jump if high OR Have pb in digital mode, and use cmp pb, -1 with jz/je to jump if high Any of these should work as a "jump if port is high" snippet Test code to show what a port reads in as:

mov ports, 0010b
;mov adc, 0010b
mov a, pb
sp:
jmp sp

Comment/uncomment the second line to switch between digital/analog modes respectively.

Register a will have in it whatever was in the back port on putting in the book. You can mouse over a in the GUI to see it's value in both hex and decimal. Technically, in digital mode, a port being high reads as decimal -1 because 2's complement 0xFF is -1 decimal, which is why cmp pb, 1 wasn't working.

Just read more into the issue, saw this:

tried with 0xff but couldn't get that to work either.

I tried this program:

mov ports, 0010b
m:cmp pb, 0xFF
jz yes
jmp m
yes:mov b, 0xBB
jmp m

Once pb goes high, b gets set to 0xBB as expected, therefore the comparison with 0xFF works. Tested with mod version 1.0.5-b1, on Forge 36.1.0, Minecraft 1.16.5.

stfwi commented 3 years ago

Hey guys, independent of the current PR addressing the 0x1/0xff digital values, I would recommend to use the AND instruction for bitwise checks, or compare zero, like

  MOV a, pb
  AND a, 0xff   ; or CMP a, 0x00
  JNZ powered
unpowered:
  ; do stuff
  JMP cond_done
powered:
  ; do stuff
cond_done:
 ...

That way it does not matter if the port is in digital or analog mode.

(A compare instruction is like a subtraction, except that it does not change the register, but sets or clears Carry and Zero instead. CMP a, b: The carry bit is set if a<b, zero bit if a==b, none of both if a>b). Maybe a bit-test instruction could be interesting for getting something like the bitwise comparison shown above, but without the need to MOV a, pb first (at least not if we respect the input read-only). IIRC BIT should be that on small RISC CPUs.

Keep it up guys, cheers,-

paperky commented 3 years ago

Hey guys, independent of the current PR addressing the 0x1/0xff digital values, I would recommend to use the AND instruction for bitwise checks, or compare zero, like

  MOV a, pb
  AND a, 0xff   ; or CMP a, 0x00
  JNZ powered
unpowered:
  ; do stuff
  JMP cond_done
powered:
  ; do stuff
cond_done:
 ...

That way it does not matter if the port is in digital or analog mode.

(A compare instruction is like a subtraction, except that it does not change the register, but sets or clears Carry and Zero instead. CMP a, b: The carry bit is set if a<b, zero bit if a==b, none of both if a>b).

Yeah, I've seen the Wiki page for how CMP a,b is just "subtract but only change the carry and zero flags". It's probably good to have it noted here though too for anyone that's searching that that's how CMP works, and that's why CMP isn't doing what they'd expect for certain numbers.

This snippet does work, and it's good for preserving the 0x0-0xF value of that port if it's being used in the do stuff blocks. That said, it clobbers a register. In my experience, CMP port, constant, when working with the ports in digital mode, is usually better since it doesn't clobber a register to directly CMP a port to a constant. It's one instruction less, three less if you want to preserve and restore the clobbered register using the stack, but granted directly accessing the register doesn't allow the use of boolean operators like AND or such without violating the read-only nature of the port registers in input mode. You could shorten down that snipped to this, if you're sure that pb is in Digital mode:

  CMP pb, 0x00
  JNZ powered
unpowered:
  ; do stuff
  JMP cond_done
powered:
  ; do stuff
cond_done:
  ...

There's also a case to be made regarding input to use the (as far as I can tell) unused upper nybble of the ADC register to have a "legacy" mode for Digital, where the registers read out 0xFF or 0x00 as they used to be with the pre-PR digital. It'd be nice for things like XOR a, pb, but it would prevent any other features or use of that nybble, such as setting indirection registers or just a free extra nybble of workspace.

stfwi commented 3 years ago

Hi, aye, totally, compare-zero is the best thing for single value query. The unused port bit usage is also a good aspect. The PR is related to the descriptions in the wiki, hence the change to 0x1.

Similar to the fewer cycles needed, I am wondering if the bit-testing instruction mentioned could be interesting for the new (if accepted) IDR register. To latch and check ports in one go, e.g. AND would be needed without, I mean ...

loop:
  WFE
  MOV a, idr   ; latch all I/O port states in lower nibble
  AND a, match
  JNZ case_b
case_a:
  ; do a
  JMP done
case_b:
  ; do b
done:
 ...

Bit testing replaces that with a boolean result in Z:

loop:
  WFE
  BIT idr, match
  JNZ case_b
case_a:
  ; do a
  JMP done
case_b:
  ; do b
done:
 ...

Similar to the compare-zero - without clobbering a register. Would that be a thing worth implementing?

paperky commented 3 years ago

I am wondering if the bit-testing instruction mentioned could be interesting for the new (if accepted) IDR register.

Assuming this is the mentioned proposal:

Maybe a bit-test instruction could be interesting for getting something like the bitwise comparison shown above, but without the need to MOV a, pb first

I assume that BIT value, match ANDs each bit of value with each bit of match, and sets the Z flag accordingly, with the resulting functionality being: jnz is "jump if any bits of value are also set in match", and jz is "jump if no bits of value are also set in match", like a CMP version of AND?

If this is what it'd do, I see how it's not possible to do that with CMP since subtraction can't "ignore" bits like AND can, and I see the benefits of this especially with having separate inputs mapped to bits of a register. It can't test if value matches mask directly, but that's already handled by CMP, so it definitely sounds like a QOL improvement and a useful new feature.

In the second quote, I assume the comparison referred to here, AND a, 0xFF is "test if any bit of a is set", and your proposal is to be able to replace that with BIT pb, 0xFF? It'd for sure be nice to have something that concise to use to test specific bits, especially with IDR adding a need to do that kind of bit testing.