; The SuperconBadgeV6 Assembler ; https://hackaday.io/project/191355-assembler-for-superconbadge ; Version 0.1 - convert ASCII HEX (bigendian) code string to binary loader format ; This is a text version of the code, in no particular syntax. ; Overview functionality: ; Write header, convert the first 4 hexdigits(BigEndian) to the length field (LittleEndian) ; The convert hex 3-digits opcodes (BigEndian) to binary 2-byte (LittleEndian) ; Write trailer ie. the computed checksum (LittleEndian) ; start MOV R0,0x2 ; fast=2/slow=D clock. Changed as needed. MOV [CLCK],R0 ; (also copied to padding sections where debugging) MOV R0,0xF ; Page so we see the SER-registers and the R-registers MOV [PAGE],R0 PURGE: MOV R0,[SERH] ; purge any partial input (leftover from last run, noise ...) MOV R0,[SERL] MOV R0,[RCVD] ; really empty input buffer CP R0,0 SKIP Z,1 JR PURGE ; (unfortunatly this code doesn't do what is intended) ; Output leading bytes of header - (could rewrite to loops with lookup) MOV PC,PUTBIN ; (@070) output binary R1 value MOV R1,0 ; Value=0 MOV JSR,0 ; call output it MOV JSR,0 ; twice, ie output 00 MOV R1,0xF ; Value=F MOV JSR,0 MOV JSR,0 ; twice, ie output FF MOV R1,0 ; repeat to do another 00FF MOV JSR,0 MOV JSR,0 MOV R1,0xF MOV JSR,0 MOV JSR,0 MOV R1,0xA ; and output A5C3 MOV JSR,0 MOV R1,0x5 MOV JSR,0 MOV R1,0xC MOV JSR,0 MOV R1,0x3 MOV JSR,0 ; Next the length byte - for now required in the user input, although part of the header. ; is entered "normally", ie BigEndian, with 4 digits ; initialise checksum with this MOV PC,GETHEX ; call read HEX (@080) into R1 MOV JSR,0 MOV R9,R1 ; save highest nibble MOV JSR,0 MOV R8,R1 ; do other 3... MOV JSR,0 MOV R7,R1 MOV JSR,0 MOV R6,R1 MOV PC,PUTBIN ; Output in LittleEndian order MOV R1,R7 ; Top nibble of low byte MOV JSR,0 MOV R1,R6 ; Low nibble of low byte MOV JSR,0 MOV R1,R9 ; Top nibble of top byte MOV JSR,0 MOV R1,R8 ; Low nibble of top byte MOV JSR,0 MOV R8,R8 ; couple of NOPs ... MOV R8,R8 ; now loop reading 3 ASCII HEX normal/bigendian, and outputting two bytes, littleendian. ; END is signalled by the ^D(EOT). The Hex input routine catches it and returns R0=F LOOP: MOV PC,GETHEX MOV JSR,0 CP R0,0xF ; did we see EOT SKIP NZ,1 ; JR TRAIL ; 058-040=18 - EOT => do trailer MOV R4,R1 ; Save high nibble MOV JSR,0 MOV R3,R1 ; save middle nibble MOV JSR,0 MOV R2,R1 ; save lower nibble MOV PC,PUTBIN ; MOV R1,R3 ; Middle nibble MOV JSR,0 MOV R1,R2 ; low nibble MOV JSR,0 MOV R1,0 ; padding byte, zero MOV JSR,0 MOV R1,R4 ; high nibble MOV JSR,0 MOV R8,R8 ; a few NOP for patch room whilst debugging ; accumulate checksum in R9:8:7:6 ADD R6,R2 ; Accumulate the number, right way up ADC R7,R3 ADC R8,R4 MOV R0,0 ; the paddding zero ADC R9,R0 ; to include the carry ; Loop INC R5 ; (Debugging, we see number of doublebytes output in R5) JR LOOP ; 03B-057=E4 ; do the trailer TRAIL: MOV PC,PUTBIN ; call output binary R1 value MOV R1,R7 ; output the checksum, LittleEndian MOV JSR,0 MOV R1,R6 ; MOV JSR,0 MOV R1,R9 ; MOV JSR,0 MOV R1,R8 ; MOV JSR,0 MOV R8,R8 HALT ; Actually jump back to itself. ; Could also do a RET, as the stack is empty and it will really halt PUTBIN: ; output a binary nibble. It buffers so two nibbles, first high, then low, make one byte ; Entry: R1=nibble ; Exit: R0=0 on first nibble, R0=1 on 2nd nibble ; Global: FLAG at [0x20], BUFOUT at [0x21] MOV R0,[FLAG] ; Get flag CP R0,0 ; MOV R0,R1 ; (doesnt disturb the CP result) SKIP NZ,4 ; Flag set, skip to output byte MOV [BUFOUT],R0; else store in buffer MOV R0,0xF ; and set flag MOV [FLAG],R0 RET R0,1 MOV R0,[BUFOUT]; Get buffered nibble MOV [SERH],R0 ; output it MOV R0,R1 MOV [SERL],R0 ; Output lower nibble, byte is sent MOV R0,0 ; reset flag MOV [FLAG],R0 RET R0,0 GETHEX: ; get binary value of ASCII HEX character from input. Must be uppercase, no whitespace ; Entry: - ; Exit: R0=0 : R1 value of digit, R0=F it is a control char and R1 invalid MOV R0,[RCVD] ; Is anything in input? CP R0,0 SKIP NZ,1 JR GETHEX ; 080-084=FC MOV R1,0 ; Assume a 0-9 MOV R0,[SERH] ; Get char high CP R0,4 ; Is A..F or 0..9 SKIP NZ,1 MOV R1,9 ; Adjust so low('A')=1 returns 10(10) CP R0,0 ; is it a LOW control character (eg TAB,CR ^D(EOT)) SKIP Z,3 ; yes (we dont care which) MOV R0,[SERL] ; low nibble is the value (+ the 9 for A..Z) ADD R1,R0 RET R0,0 MOV R0,[SERL] ; get the rest of char (should check if 0x4) RET R0,0xF ; Signal end.